better not-found error messages for variables and functions

This commit is contained in:
steve donovan 2018-07-16 13:01:11 +02:00
parent 8bf318c99f
commit 2bf3f5e957
2 changed files with 44 additions and 8 deletions

View File

@ -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<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 {
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,8 +95,12 @@ impl Error for EvalAltResult {
impl fmt::Display for EvalAltResult {
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())
}
}
}
#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
@ -170,12 +184,17 @@ impl Engine {
ident: ident.clone(),
args: Some(args.iter().map(|a| <Any as Any>::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::<Vec<_>>();
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<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
pub fn eval_file<T: Any + Clone>(&mut self, fname: &str) -> Result<T, EvalAltResult> {
use std::fs::File;

View File

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