FIX: Even more and better error reporting.

Addresses: #34
This commit is contained in:
Jeremy Wall 2019-02-02 16:43:29 -06:00
parent 2068063a5b
commit a74d44c171
3 changed files with 88 additions and 29 deletions

View File

@ -42,13 +42,14 @@ fn assert_build_failure(input: &str, expect: Vec<Regex>) {
for r in expect.iter() {
if !b.assert_collector.success {
if let None = r.find(&b.assert_collector.failures) {
panic!(
assert!(
false,
"[{}] was not found in Assertion Failures:\n{}",
r, b.assert_collector.failures
);
}
} else {
panic!("Building input Did not panic!");
assert!(false, "Building input Did not panic!");
}
}
}
@ -57,7 +58,11 @@ fn assert_build_failure(input: &str, expect: Vec<Regex>) {
let stack_trace = format!("{}", err);
// Look for each expect to match the string.
if let None = r.find(&stack_trace) {
panic!("[{}] was not found in stacktrace:\n{}", r, stack_trace);
assert!(
false,
"[{}] was not found in stacktrace:\n{}",
r, stack_trace
);
}
}
}
@ -224,3 +229,49 @@ fn test_assert_partial_tuple_bad_desc_compile_failures() {
],
);
}
#[test]
fn test_import_missing_path_compile_failure() {
assert_build_failure(
"import ;",
vec![
Regex::new(r"Expected import path: at <eval> line: 1, column: 8").unwrap(),
Regex::new(r"Not a String: at <eval> line: 1, column: 8").unwrap(),
],
)
}
#[test]
fn test_import_path_not_a_string_compile_failure() {
assert_build_failure(
"import 1;",
vec![
Regex::new(r"Expected import path: at <eval> line: 1, column: 8").unwrap(),
Regex::new(r"Not a String: at <eval> line: 1, column: 8").unwrap(),
],
)
}
#[test]
fn test_binary_operator_missing_operand_compile_failure() {
assert_build_failure(
"1 +",
vec![
Regex::new(r"Abort while parsing operator expression: at <eval> line: 1, column: 1")
.unwrap(),
Regex::new(r"Missing operand for binary expression: at <eval> line: 1, column: 4")
.unwrap(),
],
)
}
#[test]
fn test_binary_operator_wrong_type_on_rhs_compile_failure() {
assert_build_failure(
"1 + \"foo\";",
vec![
Regex::new(r"Expected Integer but got .foo.").unwrap(),
Regex::new(r"at <eval> line: 1, column: 5").unwrap(),
],
)
}

View File

@ -507,16 +507,17 @@ impl<'a> FileBuilder<'a> {
fn add_vals(
&self,
pos: &Position,
lpos: &Position,
rpos: &Position,
left: Rc<Val>,
right: Rc<Val>,
) -> Result<Rc<Val>, Box<dyn Error>> {
match *left {
Val::Int(i) => {
eval_binary_expr!(&Val::Int(ii), pos, right, Val::Int(i + ii), "Integer")
eval_binary_expr!(&Val::Int(ii), rpos, right, Val::Int(i + ii), "Integer")
}
Val::Float(f) => {
eval_binary_expr!(&Val::Float(ff), pos, right, Val::Float(f + ff), "Float")
eval_binary_expr!(&Val::Float(ff), rpos, right, Val::Float(f + ff), "Float")
}
Val::Str(ref s) => match right.as_ref() {
&Val::Str(ref ss) => {
@ -532,7 +533,7 @@ impl<'a> FileBuilder<'a> {
val
),
error::ErrorType::TypeFail,
pos.clone(),
rpos.clone(),
)));
}
},
@ -553,7 +554,7 @@ impl<'a> FileBuilder<'a> {
val
),
error::ErrorType::TypeFail,
pos.clone(),
rpos.clone(),
)));
}
},
@ -561,7 +562,7 @@ impl<'a> FileBuilder<'a> {
return Err(Box::new(error::BuildError::new(
format!("{} does not support the '+' operation", expr.type_name()),
error::ErrorType::Unsupported,
pos.clone(),
lpos.clone(),
)));
}
}
@ -569,22 +570,23 @@ impl<'a> FileBuilder<'a> {
fn subtract_vals(
&self,
pos: &Position,
lpos: &Position,
rpos: &Position,
left: Rc<Val>,
right: Rc<Val>,
) -> Result<Rc<Val>, Box<dyn Error>> {
match *left {
Val::Int(i) => {
eval_binary_expr!(&Val::Int(ii), pos, right, Val::Int(i - ii), "Integer")
eval_binary_expr!(&Val::Int(ii), rpos, right, Val::Int(i - ii), "Integer")
}
Val::Float(f) => {
eval_binary_expr!(&Val::Float(ff), pos, right, Val::Float(f - ff), "Float")
eval_binary_expr!(&Val::Float(ff), rpos, right, Val::Float(f - ff), "Float")
}
ref expr => {
return Err(Box::new(error::BuildError::new(
format!("{} does not support the '-' operation", expr.type_name()),
error::ErrorType::Unsupported,
pos.clone(),
lpos.clone(),
)));
}
}
@ -592,22 +594,23 @@ impl<'a> FileBuilder<'a> {
fn multiply_vals(
&self,
pos: &Position,
lpos: &Position,
rpos: &Position,
left: Rc<Val>,
right: Rc<Val>,
) -> Result<Rc<Val>, Box<dyn Error>> {
match *left {
Val::Int(i) => {
eval_binary_expr!(&Val::Int(ii), pos, right, Val::Int(i * ii), "Integer")
eval_binary_expr!(&Val::Int(ii), rpos, right, Val::Int(i * ii), "Integer")
}
Val::Float(f) => {
eval_binary_expr!(&Val::Float(ff), pos, right, Val::Float(f * ff), "Float")
eval_binary_expr!(&Val::Float(ff), rpos, right, Val::Float(f * ff), "Float")
}
ref expr => {
return Err(Box::new(error::BuildError::new(
format!("{} does not support the '*' operation", expr.type_name()),
error::ErrorType::Unsupported,
pos.clone(),
lpos.clone(),
)));
}
}
@ -615,22 +618,23 @@ impl<'a> FileBuilder<'a> {
fn divide_vals(
&self,
pos: &Position,
lpos: &Position,
rpos: &Position,
left: Rc<Val>,
right: Rc<Val>,
) -> Result<Rc<Val>, Box<dyn Error>> {
match *left {
Val::Int(i) => {
eval_binary_expr!(&Val::Int(ii), pos, right, Val::Int(i / ii), "Integer")
eval_binary_expr!(&Val::Int(ii), rpos, right, Val::Int(i / ii), "Integer")
}
Val::Float(f) => {
eval_binary_expr!(&Val::Float(ff), pos, right, Val::Float(f / ff), "Float")
eval_binary_expr!(&Val::Float(ff), rpos, right, Val::Float(f / ff), "Float")
}
ref expr => {
return Err(Box::new(error::BuildError::new(
format!("{} does not support the '*' operation", expr.type_name()),
error::ErrorType::Unsupported,
pos.clone(),
lpos.clone(),
)));
}
}
@ -976,10 +980,10 @@ impl<'a> FileBuilder<'a> {
};
match kind {
// Handle math and concatenation operators here
&BinaryExprType::Add => self.add_vals(&def.pos, left, right),
&BinaryExprType::Sub => self.subtract_vals(&def.pos, left, right),
&BinaryExprType::Mul => self.multiply_vals(&def.pos, left, right),
&BinaryExprType::Div => self.divide_vals(&def.pos, left, right),
&BinaryExprType::Add => self.add_vals(&def.pos, def.right.pos(), left, right),
&BinaryExprType::Sub => self.subtract_vals(&def.pos, def.right.pos(), left, right),
&BinaryExprType::Mul => self.multiply_vals(&def.pos, def.right.pos(), left, right),
&BinaryExprType::Div => self.divide_vals(&def.pos, def.right.pos(), left, right),
// Handle Comparison operators here
&BinaryExprType::Equal => self.do_deep_equal(&def.pos, left, right),
&BinaryExprType::GT => self.do_gt(&def.pos, left, right),

View File

@ -254,7 +254,12 @@ fn parse_operand_list<'a>(i: SliceIter<'a, Token>) -> ParseResult<'a, Vec<Elemen
// if we have successfully parsed an element and an operator then
// failing to parse a second expression is an abort since we know
// for sure now that the next expression is supposed to be there.
return Result::Abort(e);
let err = Error::caused_by(
"Missing operand for binary expression",
Box::new(e),
Box::new(_i.clone()),
);
return Result::Abort(err);
}
return Result::Fail(e);
}
@ -388,7 +393,6 @@ pub fn parse_precedence(i: SliceIter<Element>) -> Result<SliceIter<Element>, Exp
/// Parse a binary operator expression.
pub fn op_expression<'a>(i: SliceIter<'a, Token>) -> Result<SliceIter<Token>, Expression> {
// TODO(jwall): We need to implement the full on precedence climbing method here.
let preparse = parse_operand_list(i.clone());
match preparse {
Result::Fail(e) => {
@ -401,11 +405,11 @@ pub fn op_expression<'a>(i: SliceIter<'a, Token>) -> Result<SliceIter<Token>, Ex
}
Result::Abort(e) => {
let err = Error::caused_by(
"Failed while parsing operator expression",
"Abort while parsing operator expression",
Box::new(e),
Box::new(i),
);
Result::Fail(err)
Result::Abort(err)
}
Result::Incomplete(i) => Result::Incomplete(i),
Result::Complete(rest, oplist) => {