diff --git a/src/build/compile_test.rs b/src/build/compile_test.rs index 0141f23..9bc5f95 100644 --- a/src/build/compile_test.rs +++ b/src/build/compile_test.rs @@ -42,13 +42,14 @@ fn assert_build_failure(input: &str, expect: Vec) { 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) { 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 line: 1, column: 8").unwrap(), + Regex::new(r"Not a String: at 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 line: 1, column: 8").unwrap(), + Regex::new(r"Not a String: at 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 line: 1, column: 1") + .unwrap(), + Regex::new(r"Missing operand for binary expression: at 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 line: 1, column: 5").unwrap(), + ], + ) +} diff --git a/src/build/mod.rs b/src/build/mod.rs index a221b58..643844a 100644 --- a/src/build/mod.rs +++ b/src/build/mod.rs @@ -507,16 +507,17 @@ impl<'a> FileBuilder<'a> { fn add_vals( &self, - pos: &Position, + lpos: &Position, + rpos: &Position, left: Rc, right: Rc, ) -> Result, Box> { 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, right: Rc, ) -> Result, Box> { 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, right: Rc, ) -> Result, Box> { 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, right: Rc, ) -> Result, Box> { 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), diff --git a/src/parse/precedence.rs b/src/parse/precedence.rs index 0efa847..bc64b31 100644 --- a/src/parse/precedence.rs +++ b/src/parse/precedence.rs @@ -254,7 +254,12 @@ fn parse_operand_list<'a>(i: SliceIter<'a, Token>) -> ParseResult<'a, Vec) -> Result, Exp /// Parse a binary operator expression. pub fn op_expression<'a>(i: SliceIter<'a, Token>) -> Result, 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, 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) => {