diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ca2686b..436e20df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ Bug fixes * Variables introduced inside `try` blocks are now properly cleaned up upon an exception. * Off-by-one error in character positions after a comment line is now fixed. * Globally-defined constants are now encapsulated correctly inside a loaded module and no longer spill across call boundaries. +* Type names display is fixed. Script-breaking changes ----------------------- diff --git a/src/api/mod.rs b/src/api/mod.rs index 39045da7..b7d9b8f2 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -1,5 +1,7 @@ //! Module defining the public API of the Rhai engine. +pub mod type_names; + pub mod eval; pub mod run; diff --git a/src/api/type_names.rs b/src/api/type_names.rs new file mode 100644 index 00000000..8e7162a2 --- /dev/null +++ b/src/api/type_names.rs @@ -0,0 +1,132 @@ +use crate::{ + Engine, ExclusiveRange, FnPtr, ImmutableString, InclusiveRange, Instant, Position, RhaiError, + ERR, +}; +use std::any::type_name; +#[cfg(feature = "no_std")] +use std::prelude::v1::*; + +/// Map the name of a standard type into a friendly form. +#[inline] +#[must_use] +fn map_std_type_name(name: &str, shorthands: bool) -> &str { + let name = name.trim(); + + if name == type_name::() { + return if shorthands { "string" } else { "String" }; + } + if name == type_name::() || name == "ImmutableString" { + return if shorthands { + "string" + } else { + "ImmutableString" + }; + } + if name == type_name::<&str>() { + return if shorthands { "string" } else { "&str" }; + } + #[cfg(feature = "decimal")] + if name == type_name::() { + return if shorthands { "decimal" } else { "Decimal" }; + } + if name == type_name::() || name == "FnPtr" { + return if shorthands { "Fn" } else { "FnPtr" }; + } + #[cfg(not(feature = "no_index"))] + if name == type_name::() || name == "Array" { + return if shorthands { "array" } else { "Array" }; + } + #[cfg(not(feature = "no_index"))] + if name == type_name::() || name == "Blob" { + return if shorthands { "blob" } else { "Blob" }; + } + #[cfg(not(feature = "no_object"))] + if name == type_name::() || name == "Map" { + return if shorthands { "map" } else { "Map" }; + } + #[cfg(not(feature = "no_std"))] + if name == type_name::() || name == "Instant" { + return if shorthands { "timestamp" } else { "Instant" }; + } + if name == type_name::() || name == "ExclusiveRange" { + return if shorthands { + "range" + } else if cfg!(feature = "only_i32") { + "Range" + } else { + "Range" + }; + } + if name == type_name::() || name == "InclusiveRange" { + return if shorthands { + "range=" + } else if cfg!(feature = "only_i32") { + "RangeInclusive" + } else { + "RangeInclusive" + }; + } + + if name.starts_with("rhai::") { + map_std_type_name(&name[6..], shorthands) + } else { + name + } +} + +impl Engine { + /// Pretty-print a type name. + /// + /// If a type is registered via [`register_type_with_name`][Engine::register_type_with_name], + /// the type name provided for the registration will be used. + /// + /// # Panics + /// + /// Panics if the type name is `&mut`. + #[inline] + #[must_use] + pub fn map_type_name<'a>(&'a self, name: &'a str) -> &'a str { + self.type_names + .get(name) + .map(|s| s.as_str()) + .unwrap_or_else(|| map_std_type_name(name, true)) + } + + /// Format a type name. + /// + /// If a type is registered via [`register_type_with_name`][Engine::register_type_with_name], + /// the type name provided for the registration will be used. + #[cfg(feature = "metadata")] + #[inline] + #[must_use] + pub(crate) fn format_type_name<'a>(&'a self, name: &'a str) -> std::borrow::Cow<'a, str> { + if name.starts_with("&mut ") { + let x = &name[5..]; + let r = self.format_type_name(x); + return if x != r { + format!("&mut {}", r).into() + } else { + name.into() + }; + } + + self.type_names + .get(name) + .map(|s| s.as_str()) + .unwrap_or_else(|| match name { + "INT" => return type_name::(), + #[cfg(not(feature = "no_float"))] + "FLOAT" => return type_name::(), + _ => map_std_type_name(name, false), + }) + .into() + } + + /// Make a `Box<`[`EvalAltResult`][ERR::ErrorMismatchDataType]`>`. + #[inline(never)] + #[must_use] + pub(crate) fn make_type_mismatch_err(&self, typ: &str, pos: Position) -> RhaiError { + ERR::ErrorMismatchDataType(self.map_type_name(type_name::()).into(), typ.into(), pos) + .into() + } +} diff --git a/src/engine.rs b/src/engine.rs index 14206d6f..aa5a36d1 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -4,15 +4,14 @@ use crate::api::custom_syntax::CustomSyntax; use crate::func::native::{OnDebugCallback, OnParseTokenCallback, OnPrintCallback, OnVarCallback}; use crate::packages::{Package, StandardPackage}; use crate::tokenizer::Token; -use crate::types::dynamic::{map_std_type_name, Union}; +use crate::types::dynamic::{ Union}; use crate::{ - Dynamic, Identifier, ImmutableString, Module, Position, RhaiError, RhaiResult, Shared, - StaticVec, ERR, + Dynamic, Identifier, ImmutableString, Module, Position, RhaiResult, Shared, + StaticVec, }; #[cfg(feature = "no_std")] use std::prelude::v1::*; use std::{ - any::type_name, collections::{BTreeMap, BTreeSet}, fmt, num::NonZeroU8, @@ -337,59 +336,4 @@ impl Engine { result } - - /// Pretty-print a type name. - /// - /// If a type is registered via [`register_type_with_name`][Engine::register_type_with_name], - /// the type name provided for the registration will be used. - /// - /// # Panics - /// - /// Panics if the type name is `&mut`. - #[inline] - #[must_use] - pub fn map_type_name<'a>(&'a self, name: &'a str) -> &'a str { - self.type_names - .get(name) - .map(|s| s.as_str()) - .unwrap_or_else(|| map_std_type_name(name, true)) - } - - /// Format a type name. - /// - /// If a type is registered via [`register_type_with_name`][Engine::register_type_with_name], - /// the type name provided for the registration will be used. - #[cfg(feature = "metadata")] - #[inline] - #[must_use] - pub(crate) fn format_type_name<'a>(&'a self, name: &'a str) -> std::borrow::Cow<'a, str> { - if name.starts_with("&mut ") { - let x = &name[5..]; - let r = self.format_type_name(x); - return if x != r { - format!("&mut {}", r).into() - } else { - name.into() - }; - } - - self.type_names - .get(name) - .map(|s| s.as_str()) - .unwrap_or_else(|| match name { - "INT" => return type_name::(), - #[cfg(not(feature = "no_float"))] - "FLOAT" => return type_name::(), - _ => map_std_type_name(name, false), - }) - .into() - } - - /// Make a `Box<`[`EvalAltResult`][ERR::ErrorMismatchDataType]`>`. - #[inline] - #[must_use] - pub(crate) fn make_type_mismatch_err(&self, typ: &str, pos: Position) -> RhaiError { - ERR::ErrorMismatchDataType(self.map_type_name(type_name::()).into(), typ.into(), pos) - .into() - } } diff --git a/src/lib.rs b/src/lib.rs index a94f146e..ea94ed65 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -154,6 +154,8 @@ pub use eval::EvalContext; pub use func::{NativeCallContext, RegisterNativeFunction}; pub use module::{FnNamespace, Module}; pub use tokenizer::Position; +#[cfg(not(feature = "no_std"))] +pub use types::Instant; pub use types::{ Dynamic, EvalAltResult, FnPtr, ImmutableString, LexError, ParseError, ParseErrorType, Scope, }; diff --git a/src/types/dynamic.rs b/src/types/dynamic.rs index 0b8fdf80..48d0d124 100644 --- a/src/types/dynamic.rs +++ b/src/types/dynamic.rs @@ -16,11 +16,11 @@ use std::{ #[cfg(not(feature = "no_std"))] #[cfg(not(target_family = "wasm"))] -use std::time::Instant; +pub use std::time::Instant; #[cfg(not(feature = "no_std"))] #[cfg(target_family = "wasm")] -use instant::Instant; +pub use instant::Instant; /// The message: data type was checked const CHECKED: &str = "data type was checked"; @@ -543,74 +543,6 @@ impl Hash for Dynamic { } } -/// Map the name of a standard type into a friendly form. -#[inline] -#[must_use] -pub(crate) fn map_std_type_name(name: &str, shorthands: bool) -> &str { - let name = name.trim(); - - if name.starts_with("rhai::") { - return map_std_type_name(&name[6..], shorthands); - } - - if name == type_name::() { - return if shorthands { "string" } else { "String" }; - } - if name == type_name::() { - return if shorthands { - "string" - } else { - "ImmutableString" - }; - } - if name == type_name::<&str>() { - return if shorthands { "string" } else { "&str" }; - } - #[cfg(feature = "decimal")] - if name == type_name::() { - return if shorthands { "decimal" } else { "Decimal" }; - } - if name == type_name::() { - return if shorthands { "Fn" } else { "FnPtr" }; - } - #[cfg(not(feature = "no_index"))] - if name == type_name::() { - return if shorthands { "array" } else { "Array" }; - } - #[cfg(not(feature = "no_index"))] - if name == type_name::() { - return if shorthands { "blob" } else { "Blob" }; - } - #[cfg(not(feature = "no_object"))] - if name == type_name::() { - return if shorthands { "map" } else { "Map" }; - } - #[cfg(not(feature = "no_std"))] - if name == type_name::() { - return if shorthands { "timestamp" } else { "Instant" }; - } - if name == type_name::() || name == "ExclusiveRange" { - return if shorthands { - "range" - } else if cfg!(feature = "only_i32") { - "Range" - } else { - "Range" - }; - } - if name == type_name::() || name == "InclusiveRange" { - return if shorthands { - "range=" - } else if cfg!(feature = "only_i32") { - "RangeInclusive" - } else { - "RangeInclusive" - }; - } - - name -} - impl fmt::Display for Dynamic { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.0 { diff --git a/src/types/mod.rs b/src/types/mod.rs index 1012f8b1..66da654c 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -9,6 +9,8 @@ pub mod parse_error; pub mod scope; pub use dynamic::Dynamic; +#[cfg(not(feature = "no_std"))] +pub use dynamic::Instant; pub use error::EvalAltResult; pub use fn_ptr::FnPtr; pub use immutable_string::ImmutableString;