Implement better error messages for addition with incompatible types

Implements #60
This commit is contained in:
Sebastian Schmidt 2019-08-29 16:36:35 +03:00
parent 2ec3dc74c1
commit 2d1704b9a3
3 changed files with 23 additions and 10 deletions

View File

@ -214,6 +214,11 @@ impl EvalexprError {
EvalexprError::TypeError { actual, expected } EvalexprError::TypeError { actual, expected }
} }
/// Constructs `EvalexprError::WrongTypeCombination{operator, actual}`.
pub fn wrong_type_combination(operator: Operator, actual: Vec<ValueType>) -> Self {
EvalexprError::WrongTypeCombination { operator, actual }
}
/// Constructs `EvalexprError::ExpectedString{actual}`. /// Constructs `EvalexprError::ExpectedString{actual}`.
pub fn expected_string(actual: Value) -> Self { pub fn expected_string(actual: Value) -> Self {
EvalexprError::ExpectedString { actual } EvalexprError::ExpectedString { actual }

View File

@ -1,11 +1,12 @@
use crate::function::builtin::builtin_function; use crate::function::builtin::builtin_function;
use crate::{context::Context, error::*, value::Value}; use crate::{context::Context, error::*, value::Value};
use std::borrow::Borrow;
mod display; mod display;
/// An enum that represents operators in the operator tree. /// An enum that represents operators in the operator tree.
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq, Clone)]
pub enum Operator { pub enum Operator {
/// A root node in the operator tree. /// A root node in the operator tree.
/// The whole expression is stored under a root node, as well as each subexpression surrounded by parentheses. /// The whole expression is stored under a root node, as well as each subexpression surrounded by parentheses.
@ -205,9 +206,13 @@ impl Operator {
arguments[1].clone(), arguments[1].clone(),
)) ))
} }
} else if let (Ok(a), Ok(b)) = (arguments[0].as_number(), arguments[1].as_number())
{
Ok(Value::Float(a + b))
} else { } else {
Ok(Value::Float( Err(EvalexprError::wrong_type_combination(
arguments[0].as_number()? + arguments[1].as_number()?, self.clone(),
vec![arguments[0].borrow().into(), arguments[1].borrow().into()],
)) ))
} }
}, },

View File

@ -698,17 +698,20 @@ fn test_operator_assignments() {
#[test] #[test]
fn test_type_errors_in_binary_operators() { fn test_type_errors_in_binary_operators() {
// This error is bad. In future, maybe add a special error message for this kind of call. // Only addition supports incompatible types, all others work only on numbers or only on booleans.
// So only addition requires the more fancy error message.
assert_eq!( assert_eq!(
eval("4 + \"abc\""), eval("4 + \"abc\""),
Err(EvalexprError::expected_number(Value::from( Err(EvalexprError::wrong_type_combination(
"abc".to_string() Operator::Add,
))) vec![ValueType::Int, ValueType::String]
))
); );
assert_eq!( assert_eq!(
eval("\"abc\" + 4"), eval("\"abc\" + 4"),
Err(EvalexprError::expected_number(Value::from( Err(EvalexprError::wrong_type_combination(
"abc".to_string() Operator::Add,
))) vec![ValueType::String, ValueType::Int]
))
); );
} }