From 2bf3f5e9572dc4d51832b2ce087a22dd9a361fe6 Mon Sep 17 00:00:00 2001 From: steve donovan Date: Mon, 16 Jul 2018 13:01:11 +0200 Subject: [PATCH] better not-found error messages for variables and functions --- src/engine.rs | 50 ++++++++++++++++++++++++++++++++++++------ tests/mismatched_op.rs | 2 +- 2 files changed, 44 insertions(+), 8 deletions(-) diff --git a/src/engine.rs b/src/engine.rs index 7fe9a561..d43f69e5 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -14,7 +14,7 @@ use call::FunArgs; #[derive(Debug)] pub enum EvalAltResult { - ErrorFunctionNotFound, + ErrorFunctionNotFound(String), ErrorFunctionArgMismatch, ErrorFunctionCallNotSupported, ErrorIndexMismatch, @@ -29,12 +29,22 @@ pub enum EvalAltResult { Return(Box), } +impl EvalAltResult { + fn as_str(&self) -> Option<&str> { + match *self { + EvalAltResult::ErrorVariableNotFound(ref s) => Some(s.as_str()), + EvalAltResult::ErrorFunctionNotFound(ref s) => Some(s.as_str()), + _ => None + } + } +} + impl PartialEq for EvalAltResult { fn eq(&self, other: &Self) -> bool { use EvalAltResult::*; match (self, other) { - (&ErrorFunctionNotFound, &ErrorFunctionNotFound) => true, + (&ErrorFunctionNotFound(ref a), &ErrorFunctionNotFound(ref b)) => a == b, (&ErrorFunctionArgMismatch, &ErrorFunctionArgMismatch) => true, (&ErrorFunctionCallNotSupported, &ErrorFunctionCallNotSupported) => true, (&ErrorIndexMismatch, &ErrorIndexMismatch) => true, @@ -54,7 +64,7 @@ impl PartialEq for EvalAltResult { impl Error for EvalAltResult { fn description(&self) -> &str { match *self { - EvalAltResult::ErrorFunctionNotFound => "Function not found", + EvalAltResult::ErrorFunctionNotFound(_) => "Function not found", EvalAltResult::ErrorFunctionArgMismatch => "Function argument types do not match", EvalAltResult::ErrorFunctionCallNotSupported => { "Function call with > 2 argument not supported" @@ -85,7 +95,11 @@ impl Error for EvalAltResult { impl fmt::Display for EvalAltResult { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.description()) + if let Some(s) = self.as_str() { + write!(f, "{}: {}", self.description(), s) + } else { + write!(f, "{}", self.description()) + } } } @@ -170,12 +184,17 @@ impl Engine { ident: ident.clone(), args: Some(args.iter().map(|a| ::type_id(&**a)).collect()), }; - let spec1 = FnSpec { ident, args: None }; self.fns .get(&spec) - .or_else(|| self.fns.get(&spec1)) - .ok_or(EvalAltResult::ErrorFunctionNotFound) + .or_else(|| { + let spec1 = FnSpec { ident: ident.clone(), args: None }; + self.fns.get(&spec1) + }) + .ok_or_else(|| { + let typenames = args.iter().map(|x| self.nice_type_name((&**x).box_clone())).collect::>(); + EvalAltResult::ErrorFunctionNotFound(format!("{} ({})", ident, typenames.join(","))) + }) .and_then(move |f| match **f { FnIntExt::Ext(ref f) => f(args), FnIntExt::Int(ref f) => { @@ -593,6 +612,23 @@ impl Engine { } } + fn nice_type_name(&self, b: Box) -> String { + if b.is::() { + "string".into() + } else + if b.is::() { + "integer".into() + } else + if b.is::() { + "float".into() + } else + if b.is::>>() { + "array".into() + } else { + format!(" {:?}", b.type_id()) + } + } + /// Evaluate a file pub fn eval_file(&mut self, fname: &str) -> Result { use std::fs::File; diff --git a/tests/mismatched_op.rs b/tests/mismatched_op.rs index b60c1134..ef35e3a3 100644 --- a/tests/mismatched_op.rs +++ b/tests/mismatched_op.rs @@ -8,6 +8,6 @@ fn test_mismatched_op() { assert_eq!( engine.eval::("60 + \"hello\""), - Err(EvalAltResult::ErrorFunctionNotFound) + Err(EvalAltResult::ErrorFunctionNotFound("+ (integer,string)".into())) ); }