Merge pull request #76 from stevedonovan/master

better not-found error messages for variables and functions
This commit is contained in:
Lukáš Hozda [magnusi] 2018-07-20 18:19:19 +02:00 committed by GitHub
commit 92716670fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 44 additions and 8 deletions

View File

@ -14,7 +14,7 @@ use call::FunArgs;
#[derive(Debug)] #[derive(Debug)]
pub enum EvalAltResult { pub enum EvalAltResult {
ErrorFunctionNotFound, ErrorFunctionNotFound(String),
ErrorFunctionArgMismatch, ErrorFunctionArgMismatch,
ErrorFunctionCallNotSupported, ErrorFunctionCallNotSupported,
ErrorIndexMismatch, ErrorIndexMismatch,
@ -29,12 +29,22 @@ pub enum EvalAltResult {
Return(Box<Any>), Return(Box<Any>),
} }
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 { impl PartialEq for EvalAltResult {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
use EvalAltResult::*; use EvalAltResult::*;
match (self, other) { match (self, other) {
(&ErrorFunctionNotFound, &ErrorFunctionNotFound) => true, (&ErrorFunctionNotFound(ref a), &ErrorFunctionNotFound(ref b)) => a == b,
(&ErrorFunctionArgMismatch, &ErrorFunctionArgMismatch) => true, (&ErrorFunctionArgMismatch, &ErrorFunctionArgMismatch) => true,
(&ErrorFunctionCallNotSupported, &ErrorFunctionCallNotSupported) => true, (&ErrorFunctionCallNotSupported, &ErrorFunctionCallNotSupported) => true,
(&ErrorIndexMismatch, &ErrorIndexMismatch) => true, (&ErrorIndexMismatch, &ErrorIndexMismatch) => true,
@ -54,7 +64,7 @@ impl PartialEq for EvalAltResult {
impl Error for EvalAltResult { impl Error for EvalAltResult {
fn description(&self) -> &str { fn description(&self) -> &str {
match *self { match *self {
EvalAltResult::ErrorFunctionNotFound => "Function not found", EvalAltResult::ErrorFunctionNotFound(_) => "Function not found",
EvalAltResult::ErrorFunctionArgMismatch => "Function argument types do not match", EvalAltResult::ErrorFunctionArgMismatch => "Function argument types do not match",
EvalAltResult::ErrorFunctionCallNotSupported => { EvalAltResult::ErrorFunctionCallNotSupported => {
"Function call with > 2 argument not supported" "Function call with > 2 argument not supported"
@ -85,9 +95,13 @@ impl Error for EvalAltResult {
impl fmt::Display for EvalAltResult { impl fmt::Display for EvalAltResult {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(s) = self.as_str() {
write!(f, "{}: {}", self.description(), s)
} else {
write!(f, "{}", self.description()) write!(f, "{}", self.description())
} }
} }
}
#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)] #[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub struct FnSpec { pub struct FnSpec {
@ -170,12 +184,17 @@ impl Engine {
ident: ident.clone(), ident: ident.clone(),
args: Some(args.iter().map(|a| <Any as Any>::type_id(&**a)).collect()), args: Some(args.iter().map(|a| <Any as Any>::type_id(&**a)).collect()),
}; };
let spec1 = FnSpec { ident, args: None };
self.fns self.fns
.get(&spec) .get(&spec)
.or_else(|| self.fns.get(&spec1)) .or_else(|| {
.ok_or(EvalAltResult::ErrorFunctionNotFound) 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::<Vec<_>>();
EvalAltResult::ErrorFunctionNotFound(format!("{} ({})", ident, typenames.join(",")))
})
.and_then(move |f| match **f { .and_then(move |f| match **f {
FnIntExt::Ext(ref f) => f(args), FnIntExt::Ext(ref f) => f(args),
FnIntExt::Int(ref f) => { FnIntExt::Int(ref f) => {
@ -593,6 +612,23 @@ impl Engine {
} }
} }
fn nice_type_name(&self, b: Box<Any>) -> String {
if b.is::<String>() {
"string".into()
} else
if b.is::<i64>() {
"integer".into()
} else
if b.is::<f64>() {
"float".into()
} else
if b.is::<Vec<Box<Any>>>() {
"array".into()
} else {
format!("<unknown> {:?}", b.type_id())
}
}
/// Evaluate a file /// Evaluate a file
pub fn eval_file<T: Any + Clone>(&mut self, fname: &str) -> Result<T, EvalAltResult> { pub fn eval_file<T: Any + Clone>(&mut self, fname: &str) -> Result<T, EvalAltResult> {
use std::fs::File; use std::fs::File;

View File

@ -8,6 +8,6 @@ fn test_mismatched_op() {
assert_eq!( assert_eq!(
engine.eval::<i64>("60 + \"hello\""), engine.eval::<i64>("60 + \"hello\""),
Err(EvalAltResult::ErrorFunctionNotFound) Err(EvalAltResult::ErrorFunctionNotFound("+ (integer,string)".into()))
); );
} }