From 3fb2f543bb8ed867a8090161140f3dc4cddf90e8 Mon Sep 17 00:00:00 2001 From: steve donovan Date: Sun, 22 Jul 2018 11:43:21 +0200 Subject: [PATCH] Engine::register_type_name for nice error messages for arbitrary types --- src/engine.rs | 57 ++++++++++++++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/src/engine.rs b/src/engine.rs index d43f69e5..aeb3551d 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -22,7 +22,7 @@ pub enum EvalAltResult { ErrorVariableNotFound(String), ErrorFunctionArityNotSupported, ErrorAssignmentToUnknownLHS, - ErrorMismatchOutputType, + ErrorMismatchOutputType(String), ErrorCantOpenScriptFile, InternalErrorMalformedDotExpression, LoopBreak, @@ -34,6 +34,7 @@ impl EvalAltResult { match *self { EvalAltResult::ErrorVariableNotFound(ref s) => Some(s.as_str()), EvalAltResult::ErrorFunctionNotFound(ref s) => Some(s.as_str()), + EvalAltResult::ErrorMismatchOutputType(ref s) => Some(s.as_str()), _ => None } } @@ -52,7 +53,7 @@ impl PartialEq for EvalAltResult { (&ErrorVariableNotFound(ref a), &ErrorVariableNotFound(ref b)) => a == b, (&ErrorFunctionArityNotSupported, &ErrorFunctionArityNotSupported) => true, (&ErrorAssignmentToUnknownLHS, &ErrorAssignmentToUnknownLHS) => true, - (&ErrorMismatchOutputType, &ErrorMismatchOutputType) => true, + (&ErrorMismatchOutputType(ref a), &ErrorMismatchOutputType(ref b)) => a == b, (&ErrorCantOpenScriptFile, &ErrorCantOpenScriptFile) => true, (&InternalErrorMalformedDotExpression, &InternalErrorMalformedDotExpression) => true, (&LoopBreak, &LoopBreak) => true, @@ -78,7 +79,7 @@ impl Error for EvalAltResult { EvalAltResult::ErrorAssignmentToUnknownLHS => { "Assignment to an unsupported left-hand side" } - EvalAltResult::ErrorMismatchOutputType => "Cast of output failed", + EvalAltResult::ErrorMismatchOutputType(_) => "Cast of output failed", EvalAltResult::ErrorCantOpenScriptFile => "Cannot open script file", EvalAltResult::InternalErrorMalformedDotExpression => { "[Internal error] Unexpected expression in dot expression" @@ -123,10 +124,11 @@ pub struct FnSpec { /// } /// } /// ``` -#[derive(Clone)] +// #[derive(Clone)] pub struct Engine { /// A hashmap containing all functions known to the engine pub fns: HashMap>, + pub type_names: HashMap, } pub enum FnIntExt { @@ -163,7 +165,7 @@ impl Engine { .and_then(|b| { b.downcast() .map(|b| *b) - .map_err(|_| EvalAltResult::ErrorMismatchOutputType) + .map_err(|a| EvalAltResult::ErrorMismatchOutputType(self.nice_type_name(a))) }) } @@ -228,6 +230,13 @@ impl Engine { // currently a no-op, exists for future extensibility } + /// Register a type, providing a name for nice error messages. + pub fn register_type_name(&mut self, name: &str) { + self.register_type::(); + debug_println!("register type {}: {:?}", name, TypeId::of::()); + self.type_names.insert(TypeId::of::(), name.into()); + } + /// Register a get function for a member of a registered type pub fn register_get(&mut self, name: &str, get_fn: F) where @@ -613,17 +622,9 @@ 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() + let tid = (&*b).type_id(); + if let Some(name) = self.type_names.get(&tid) { + name.to_string() } else { format!(" {:?}", b.type_id()) } @@ -692,7 +693,7 @@ impl Engine { match x.downcast::() { Ok(out) => Ok(*out), - Err(_) => Err(EvalAltResult::ErrorMismatchOutputType), + Err(a) => Err(EvalAltResult::ErrorMismatchOutputType(self.nice_type_name(a))), } } Err(_) => Err(EvalAltResult::ErrorFunctionArgMismatch), @@ -775,15 +776,17 @@ impl Engine { /// Register the default library. That means, numberic types, char, bool /// String, arithmetics and string concatenations. pub fn register_default_lib(engine: &mut Engine) { - engine.register_type::(); - engine.register_type::(); - engine.register_type::(); - engine.register_type::(); - engine.register_type::(); - engine.register_type::(); - engine.register_type::(); - engine.register_type::(); - engine.register_type::(); + engine.register_type_name::("i32"); + engine.register_type_name::("u32"); + engine.register_type_name::("integer"); + engine.register_type_name::("u64"); + engine.register_type_name::("usize"); + engine.register_type_name::("f64"); + engine.register_type_name::("float"); + engine.register_type_name::("string"); + engine.register_type_name::("char"); + engine.register_type_name::("boolean"); + engine.register_type_name::>>("array"); macro_rules! reg_op { ($engine:expr, $x:expr, $op:expr, $( $y:ty ),*) => ( @@ -871,12 +874,14 @@ impl Engine { // FIXME? Registering array lookups are a special case because we want to return boxes // directly let ent = engine.fns.entry("[]".to_string()).or_insert_with(Vec::new); // (*ent).push(FnType::ExternalFn2(Box::new(idx))); + } /// Make a new engine pub fn new() -> Engine { let mut engine = Engine { fns: HashMap::new(), + type_names: HashMap::new(), }; Engine::register_default_lib(&mut engine);