Better type display.
This commit is contained in:
parent
bdc7b69266
commit
1b7ffdf408
@ -4,6 +4,10 @@ Rhai Release Notes
|
|||||||
Version 0.17.0
|
Version 0.17.0
|
||||||
==============
|
==============
|
||||||
|
|
||||||
|
Breaking changes
|
||||||
|
----------------
|
||||||
|
|
||||||
|
* `EvalAltResult::ErrorMismatchOutputType` has an extra argument containing the name of the requested type.
|
||||||
|
|
||||||
Version 0.16.1
|
Version 0.16.1
|
||||||
==============
|
==============
|
||||||
|
21
src/any.rs
21
src/any.rs
@ -202,6 +202,27 @@ impl Dynamic {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Map the name of a standard type into a friendly form.
|
||||||
|
pub(crate) fn map_std_type_name(name: &str) -> &str {
|
||||||
|
if name == type_name::<String>() {
|
||||||
|
"string"
|
||||||
|
} else if name == type_name::<ImmutableString>() {
|
||||||
|
"string"
|
||||||
|
} else if name == type_name::<&str>() {
|
||||||
|
"string"
|
||||||
|
} else if name == type_name::<Map>() {
|
||||||
|
"map"
|
||||||
|
} else if name == type_name::<Array>() {
|
||||||
|
"array"
|
||||||
|
} else if name == type_name::<FnPtr>() {
|
||||||
|
"Fn"
|
||||||
|
} else if name == type_name::<Instant>() {
|
||||||
|
"timestamp"
|
||||||
|
} else {
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Display for Dynamic {
|
impl fmt::Display for Dynamic {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match &self.0 {
|
match &self.0 {
|
||||||
|
10
src/api.rs
10
src/api.rs
@ -976,11 +976,12 @@ impl Engine {
|
|||||||
let mut mods = Imports::new();
|
let mut mods = Imports::new();
|
||||||
let (result, _) = self.eval_ast_with_scope_raw(scope, &mut mods, ast)?;
|
let (result, _) = self.eval_ast_with_scope_raw(scope, &mut mods, ast)?;
|
||||||
|
|
||||||
let return_type = self.map_type_name(result.type_name());
|
let typ = self.map_type_name(result.type_name());
|
||||||
|
|
||||||
return result.try_cast::<T>().ok_or_else(|| {
|
return result.try_cast::<T>().ok_or_else(|| {
|
||||||
Box::new(EvalAltResult::ErrorMismatchOutputType(
|
Box::new(EvalAltResult::ErrorMismatchOutputType(
|
||||||
return_type.into(),
|
self.map_type_name(type_name::<T>()).into(),
|
||||||
|
typ.into(),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
))
|
))
|
||||||
});
|
});
|
||||||
@ -1123,11 +1124,12 @@ impl Engine {
|
|||||||
let mut arg_values = args.into_vec();
|
let mut arg_values = args.into_vec();
|
||||||
let result = self.call_fn_dynamic_raw(scope, ast, name, arg_values.as_mut())?;
|
let result = self.call_fn_dynamic_raw(scope, ast, name, arg_values.as_mut())?;
|
||||||
|
|
||||||
let return_type = self.map_type_name(result.type_name());
|
let typ = self.map_type_name(result.type_name());
|
||||||
|
|
||||||
return result.try_cast().ok_or_else(|| {
|
return result.try_cast().ok_or_else(|| {
|
||||||
Box::new(EvalAltResult::ErrorMismatchOutputType(
|
Box::new(EvalAltResult::ErrorMismatchOutputType(
|
||||||
return_type.into(),
|
self.map_type_name(type_name::<T>()).into(),
|
||||||
|
typ.into(),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
))
|
))
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//! Main module defining the script evaluation `Engine`.
|
//! Main module defining the script evaluation `Engine`.
|
||||||
|
|
||||||
use crate::any::{Dynamic, Union, Variant};
|
use crate::any::{map_std_type_name, Dynamic, Union, Variant};
|
||||||
use crate::calc_fn_hash;
|
use crate::calc_fn_hash;
|
||||||
use crate::error::ParseErrorType;
|
use crate::error::ParseErrorType;
|
||||||
use crate::fn_native::{CallableFunction, Callback, FnCallArgs, FnPtr};
|
use crate::fn_native::{CallableFunction, Callback, FnCallArgs, FnPtr};
|
||||||
@ -18,7 +18,7 @@ use crate::utils::StaticVec;
|
|||||||
use crate::parser::FLOAT;
|
use crate::parser::FLOAT;
|
||||||
|
|
||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
any::TypeId,
|
any::{type_name, TypeId},
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
boxed::Box,
|
boxed::Box,
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
@ -816,9 +816,10 @@ impl Engine {
|
|||||||
// See if the function match print/debug (which requires special processing)
|
// See if the function match print/debug (which requires special processing)
|
||||||
return Ok(match fn_name {
|
return Ok(match fn_name {
|
||||||
KEYWORD_PRINT => (
|
KEYWORD_PRINT => (
|
||||||
(self.print)(result.as_str().map_err(|type_name| {
|
(self.print)(result.as_str().map_err(|typ| {
|
||||||
Box::new(EvalAltResult::ErrorMismatchOutputType(
|
Box::new(EvalAltResult::ErrorMismatchOutputType(
|
||||||
type_name.into(),
|
self.map_type_name(type_name::<ImmutableString>()).into(),
|
||||||
|
typ.into(),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
))
|
))
|
||||||
})?)
|
})?)
|
||||||
@ -826,9 +827,10 @@ impl Engine {
|
|||||||
false,
|
false,
|
||||||
),
|
),
|
||||||
KEYWORD_DEBUG => (
|
KEYWORD_DEBUG => (
|
||||||
(self.debug)(result.as_str().map_err(|type_name| {
|
(self.debug)(result.as_str().map_err(|typ| {
|
||||||
Box::new(EvalAltResult::ErrorMismatchOutputType(
|
Box::new(EvalAltResult::ErrorMismatchOutputType(
|
||||||
type_name.into(),
|
self.map_type_name(type_name::<ImmutableString>()).into(),
|
||||||
|
typ.into(),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
))
|
))
|
||||||
})?)
|
})?)
|
||||||
@ -1064,8 +1066,12 @@ impl Engine {
|
|||||||
lib: &Module,
|
lib: &Module,
|
||||||
script: &Dynamic,
|
script: &Dynamic,
|
||||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
let script = script.as_str().map_err(|type_name| {
|
let script = script.as_str().map_err(|typ| {
|
||||||
EvalAltResult::ErrorMismatchOutputType(type_name.into(), Position::none())
|
EvalAltResult::ErrorMismatchOutputType(
|
||||||
|
self.map_type_name(type_name::<ImmutableString>()).into(),
|
||||||
|
typ.into(),
|
||||||
|
Position::none(),
|
||||||
|
)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
// Compile the script text
|
// Compile the script text
|
||||||
@ -1873,9 +1879,10 @@ impl Engine {
|
|||||||
self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?;
|
self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?;
|
||||||
return arg_value
|
return arg_value
|
||||||
.take_immutable_string()
|
.take_immutable_string()
|
||||||
.map_err(|type_name| {
|
.map_err(|typ| {
|
||||||
Box::new(EvalAltResult::ErrorMismatchOutputType(
|
Box::new(EvalAltResult::ErrorMismatchOutputType(
|
||||||
type_name.into(),
|
self.map_type_name(type_name::<ImmutableString>()).into(),
|
||||||
|
typ.into(),
|
||||||
expr.position(),
|
expr.position(),
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
@ -2524,7 +2531,7 @@ impl Engine {
|
|||||||
self.type_names
|
self.type_names
|
||||||
.get(name)
|
.get(name)
|
||||||
.map(String::as_str)
|
.map(String::as_str)
|
||||||
.unwrap_or(name)
|
.unwrap_or(map_std_type_name(name))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,8 +74,8 @@ pub enum EvalAltResult {
|
|||||||
/// Assignment to a constant variable.
|
/// Assignment to a constant variable.
|
||||||
ErrorAssignmentToConstant(String, Position),
|
ErrorAssignmentToConstant(String, Position),
|
||||||
/// Returned type is not the same as the required output type.
|
/// Returned type is not the same as the required output type.
|
||||||
/// Wrapped value is the type of the actual result.
|
/// Wrapped values are the type requested and type of the actual result.
|
||||||
ErrorMismatchOutputType(String, Position),
|
ErrorMismatchOutputType(String, String, Position),
|
||||||
/// Inappropriate member access.
|
/// Inappropriate member access.
|
||||||
ErrorDotExpr(String, Position),
|
ErrorDotExpr(String, Position),
|
||||||
/// Arithmetic error encountered. Wrapped value is the error message.
|
/// Arithmetic error encountered. Wrapped value is the error message.
|
||||||
@ -141,7 +141,7 @@ impl EvalAltResult {
|
|||||||
"Assignment to an unsupported left-hand side expression"
|
"Assignment to an unsupported left-hand side expression"
|
||||||
}
|
}
|
||||||
Self::ErrorAssignmentToConstant(_, _) => "Assignment to a constant variable",
|
Self::ErrorAssignmentToConstant(_, _) => "Assignment to a constant variable",
|
||||||
Self::ErrorMismatchOutputType(_, _) => "Output type is incorrect",
|
Self::ErrorMismatchOutputType(_, _, _) => "Output type is incorrect",
|
||||||
Self::ErrorInExpr(_) => "Malformed 'in' expression",
|
Self::ErrorInExpr(_) => "Malformed 'in' expression",
|
||||||
Self::ErrorDotExpr(_, _) => "Malformed dot expression",
|
Self::ErrorDotExpr(_, _) => "Malformed dot expression",
|
||||||
Self::ErrorArithmetic(_, _) => "Arithmetic error",
|
Self::ErrorArithmetic(_, _) => "Arithmetic error",
|
||||||
@ -202,7 +202,9 @@ impl fmt::Display for EvalAltResult {
|
|||||||
Self::ErrorRuntime(s, _) => f.write_str(if s.is_empty() { desc } else { s })?,
|
Self::ErrorRuntime(s, _) => f.write_str(if s.is_empty() { desc } else { s })?,
|
||||||
|
|
||||||
Self::ErrorAssignmentToConstant(s, _) => write!(f, "{}: '{}'", desc, s)?,
|
Self::ErrorAssignmentToConstant(s, _) => write!(f, "{}: '{}'", desc, s)?,
|
||||||
Self::ErrorMismatchOutputType(s, _) => write!(f, "{}: {}", desc, s)?,
|
Self::ErrorMismatchOutputType(r, s, _) => {
|
||||||
|
write!(f, "{} (expecting {}): {}", desc, s, r)?
|
||||||
|
}
|
||||||
Self::ErrorArithmetic(s, _) => f.write_str(s)?,
|
Self::ErrorArithmetic(s, _) => f.write_str(s)?,
|
||||||
|
|
||||||
Self::ErrorLoopBreak(_, _) => f.write_str(desc)?,
|
Self::ErrorLoopBreak(_, _) => f.write_str(desc)?,
|
||||||
@ -289,7 +291,7 @@ impl EvalAltResult {
|
|||||||
| Self::ErrorModuleNotFound(_, pos)
|
| Self::ErrorModuleNotFound(_, pos)
|
||||||
| Self::ErrorAssignmentToUnknownLHS(pos)
|
| Self::ErrorAssignmentToUnknownLHS(pos)
|
||||||
| Self::ErrorAssignmentToConstant(_, pos)
|
| Self::ErrorAssignmentToConstant(_, pos)
|
||||||
| Self::ErrorMismatchOutputType(_, pos)
|
| Self::ErrorMismatchOutputType(_, _, pos)
|
||||||
| Self::ErrorInExpr(pos)
|
| Self::ErrorInExpr(pos)
|
||||||
| Self::ErrorDotExpr(_, pos)
|
| Self::ErrorDotExpr(_, pos)
|
||||||
| Self::ErrorArithmetic(_, pos)
|
| Self::ErrorArithmetic(_, pos)
|
||||||
@ -329,7 +331,7 @@ impl EvalAltResult {
|
|||||||
| Self::ErrorModuleNotFound(_, pos)
|
| Self::ErrorModuleNotFound(_, pos)
|
||||||
| Self::ErrorAssignmentToUnknownLHS(pos)
|
| Self::ErrorAssignmentToUnknownLHS(pos)
|
||||||
| Self::ErrorAssignmentToConstant(_, pos)
|
| Self::ErrorAssignmentToConstant(_, pos)
|
||||||
| Self::ErrorMismatchOutputType(_, pos)
|
| Self::ErrorMismatchOutputType(_, _, pos)
|
||||||
| Self::ErrorInExpr(pos)
|
| Self::ErrorInExpr(pos)
|
||||||
| Self::ErrorDotExpr(_, pos)
|
| Self::ErrorDotExpr(_, pos)
|
||||||
| Self::ErrorArithmetic(_, pos)
|
| Self::ErrorArithmetic(_, pos)
|
||||||
|
@ -6,14 +6,14 @@ fn test_mismatched_op() {
|
|||||||
|
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
*engine.eval::<INT>(r#""hello, " + "world!""#).expect_err("expects error"),
|
*engine.eval::<INT>(r#""hello, " + "world!""#).expect_err("expects error"),
|
||||||
EvalAltResult::ErrorMismatchOutputType(err, _) if err == "string"
|
EvalAltResult::ErrorMismatchOutputType(need, actual, _) if need == std::any::type_name::<INT>() && actual == "string"
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
fn test_mismatched_op_custom_type() {
|
fn test_mismatched_op_custom_type() {
|
||||||
#[derive(Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct TestStruct {
|
struct TestStruct {
|
||||||
x: INT,
|
x: INT,
|
||||||
}
|
}
|
||||||
@ -28,19 +28,14 @@ fn test_mismatched_op_custom_type() {
|
|||||||
engine.register_type_with_name::<TestStruct>("TestStruct");
|
engine.register_type_with_name::<TestStruct>("TestStruct");
|
||||||
engine.register_fn("new_ts", TestStruct::new);
|
engine.register_fn("new_ts", TestStruct::new);
|
||||||
|
|
||||||
let r = engine
|
|
||||||
.eval::<INT>("60 + new_ts()")
|
|
||||||
.expect_err("expects error");
|
|
||||||
|
|
||||||
#[cfg(feature = "only_i32")]
|
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
*r,
|
*engine.eval::<INT>("60 + new_ts()").expect_err("should error"),
|
||||||
EvalAltResult::ErrorFunctionNotFound(err, _) if err == "+ (i32, TestStruct)"
|
EvalAltResult::ErrorFunctionNotFound(err, _) if err == format!("+ ({}, TestStruct)", std::any::type_name::<INT>())
|
||||||
));
|
));
|
||||||
|
|
||||||
#[cfg(not(feature = "only_i32"))]
|
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
*r,
|
*engine.eval::<TestStruct>("42").expect_err("should error"),
|
||||||
EvalAltResult::ErrorFunctionNotFound(err, _) if err == "+ (i64, TestStruct)"
|
EvalAltResult::ErrorMismatchOutputType(need, actual, _)
|
||||||
|
if need == "TestStruct" && actual == std::any::type_name::<INT>()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user