diff --git a/src/api/register.rs b/src/api/register.rs index 71ef20e9..07fe973b 100644 --- a/src/api/register.rs +++ b/src/api/register.rs @@ -60,12 +60,12 @@ impl Engine { #[cfg(feature = "metadata")] let mut param_type_names: crate::StaticVec<_> = F::param_names() .iter() - .map(|ty| format!("_: {}", self.map_type_name(ty))) + .map(|ty| format!("_: {}", self.format_type_name(ty))) .collect(); #[cfg(feature = "metadata")] if F::return_type() != TypeId::of::<()>() { - param_type_names.push(self.map_type_name(F::return_type_name()).into()); + param_type_names.push(self.format_type_name(F::return_type_name()).into()); } #[cfg(feature = "metadata")] @@ -122,9 +122,9 @@ impl Engine { #[cfg(feature = "metadata")] let param_type_names: crate::StaticVec<_> = F::param_names() .iter() - .map(|ty| format!("_: {}", self.map_type_name(ty))) + .map(|ty| format!("_: {}", self.format_type_name(ty))) .chain(std::iter::once( - self.map_type_name(F::return_type_name()).into(), + self.format_type_name(F::return_type_name()).into(), )) .collect(); diff --git a/src/engine.rs b/src/engine.rs index 8bbe3046..58abe68b 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -329,13 +329,47 @@ impl Engine { /// /// 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)) + .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]`>`. diff --git a/src/eval/chaining.rs b/src/eval/chaining.rs index d2589f0b..ee225503 100644 --- a/src/eval/chaining.rs +++ b/src/eval/chaining.rs @@ -968,18 +968,11 @@ impl Engine { _ if use_indexers => { let args = &mut [target, &mut idx]; let hash_get = crate::ast::FnCallHashes::from_native(global.hash_idx_get()); + let fn_name = crate::engine::FN_IDX_GET; + let pos = Position::NONE; + self.exec_fn_call( - global, - state, - lib, - crate::engine::FN_IDX_GET, - hash_get, - args, - true, - true, - Position::NONE, - None, - level, + global, state, lib, fn_name, hash_get, args, true, true, pos, None, level, ) .map(|(v, _)| v.into()) } diff --git a/src/func/register.rs b/src/func/register.rs index 70085821..90a1e01c 100644 --- a/src/func/register.rs +++ b/src/func/register.rs @@ -107,8 +107,8 @@ macro_rules! def_register { // ^ function ABI type // ^ function parameter generic type name (A, B, C etc.) // ^ call argument(like A, *B, &mut C etc) - // ^ function parameter marker type (T, Ref or Mut) - // ^ function parameter actual type (T, &T or &mut T) + // ^ function parameter marker type (A, Ref or Mut) + // ^ function parameter actual type (A, &B or &mut C) // ^ argument let statement impl< @@ -117,7 +117,7 @@ macro_rules! def_register { RET: Variant + Clone > RegisterNativeFunction<($($mark,)*), ()> for FN { #[inline(always)] fn param_types() -> Box<[TypeId]> { vec![$(TypeId::of::<$par>()),*].into_boxed_slice() } - #[cfg(feature = "metadata")] #[inline(always)] fn param_names() -> Box<[&'static str]> { vec![$(std::any::type_name::<$par>()),*].into_boxed_slice() } + #[cfg(feature = "metadata")] #[inline(always)] fn param_names() -> Box<[&'static str]> { vec![$(std::any::type_name::<$param>()),*].into_boxed_slice() } #[cfg(feature = "metadata")] #[inline(always)] fn return_type() -> TypeId { TypeId::of::() } #[cfg(feature = "metadata")] #[inline(always)] fn return_type_name() -> &'static str { std::any::type_name::() } #[inline(always)] fn into_callable_function(self) -> CallableFunction { @@ -145,7 +145,7 @@ macro_rules! def_register { RET: Variant + Clone > RegisterNativeFunction<(NativeCallContext<'static>, $($mark,)*), ()> for FN { #[inline(always)] fn param_types() -> Box<[TypeId]> { vec![$(TypeId::of::<$par>()),*].into_boxed_slice() } - #[cfg(feature = "metadata")] #[inline(always)] fn param_names() -> Box<[&'static str]> { vec![$(std::any::type_name::<$par>()),*].into_boxed_slice() } + #[cfg(feature = "metadata")] #[inline(always)] fn param_names() -> Box<[&'static str]> { vec![$(std::any::type_name::<$param>()),*].into_boxed_slice() } #[cfg(feature = "metadata")] #[inline(always)] fn return_type() -> TypeId { TypeId::of::() } #[cfg(feature = "metadata")] #[inline(always)] fn return_type_name() -> &'static str { std::any::type_name::() } #[inline(always)] fn into_callable_function(self) -> CallableFunction { @@ -173,7 +173,7 @@ macro_rules! def_register { RET: Variant + Clone > RegisterNativeFunction<($($mark,)*), RhaiResultOf> for FN { #[inline(always)] fn param_types() -> Box<[TypeId]> { vec![$(TypeId::of::<$par>()),*].into_boxed_slice() } - #[cfg(feature = "metadata")] #[inline(always)] fn param_names() -> Box<[&'static str]> { vec![$(std::any::type_name::<$par>()),*].into_boxed_slice() } + #[cfg(feature = "metadata")] #[inline(always)] fn param_names() -> Box<[&'static str]> { vec![$(std::any::type_name::<$param>()),*].into_boxed_slice() } #[cfg(feature = "metadata")] #[inline(always)] fn return_type() -> TypeId { TypeId::of::>() } #[cfg(feature = "metadata")] #[inline(always)] fn return_type_name() -> &'static str { std::any::type_name::>() } #[inline(always)] fn into_callable_function(self) -> CallableFunction { @@ -198,7 +198,7 @@ macro_rules! def_register { RET: Variant + Clone > RegisterNativeFunction<(NativeCallContext<'static>, $($mark,)*), RhaiResultOf> for FN { #[inline(always)] fn param_types() -> Box<[TypeId]> { vec![$(TypeId::of::<$par>()),*].into_boxed_slice() } - #[cfg(feature = "metadata")] #[inline(always)] fn param_names() -> Box<[&'static str]> { vec![$(std::any::type_name::<$par>()),*].into_boxed_slice() } + #[cfg(feature = "metadata")] #[inline(always)] fn param_names() -> Box<[&'static str]> { vec![$(std::any::type_name::<$param>()),*].into_boxed_slice() } #[cfg(feature = "metadata")] #[inline(always)] fn return_type() -> TypeId { TypeId::of::>() } #[cfg(feature = "metadata")] #[inline(always)] fn return_type_name() -> &'static str { std::any::type_name::>() } #[inline(always)] fn into_callable_function(self) -> CallableFunction { diff --git a/src/module/mod.rs b/src/module/mod.rs index 51ce2653..8181edce 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -92,18 +92,60 @@ impl FuncInfo { /// `()` is cleared. /// [`RhaiResult`][crate::RhaiResult] and [`RhaiResultOf`] are expanded. #[cfg(feature = "metadata")] - pub fn format_return_type(typ: &str) -> std::borrow::Cow { + pub fn format_type(typ: &str, is_return_type: bool) -> std::borrow::Cow { const RHAI_RESULT_TYPE: &str = "RhaiResult"; const RHAI_RESULT_TYPE_EXPAND: &str = "Result>"; const RHAI_RESULT_OF_TYPE: &str = "RhaiResultOf<"; const RHAI_RESULT_OF_TYPE_EXPAND: &str = "Result<{}, Box>"; + const RHAI_RANGE: &str = "ExclusiveRange"; + const RHAI_RANGE_TYPE: &str = "Range<"; + const RHAI_RANGE_EXPAND: &str = "Range<{}>"; + const RHAI_INCLUSIVE_RANGE: &str = "InclusiveRange"; + const RHAI_INCLUSIVE_RANGE_TYPE: &str = "RangeInclusive<"; + const RHAI_INCLUSIVE_RANGE_EXPAND: &str = "RangeInclusive<{}>"; + + let typ = typ.trim(); + + if typ.starts_with("rhai::") { + return Self::format_type(&typ[6..], is_return_type); + } else if typ.starts_with("&mut ") { + let x = &typ[5..]; + let r = Self::format_type(x, false); + return if r == x { + typ.into() + } else { + format!("&mut {}", r).into() + }; + } match typ { - "" | "()" => "".into(), + "" | "()" if is_return_type => "".into(), + "INT" => std::any::type_name::().into(), + #[cfg(not(feature = "no_float"))] + "FLOAT" => std::any::type_name::().into(), + RHAI_RANGE => RHAI_RANGE_EXPAND + .replace("{}", std::any::type_name::()) + .into(), + RHAI_INCLUSIVE_RANGE => RHAI_INCLUSIVE_RANGE_EXPAND + .replace("{}", std::any::type_name::()) + .into(), RHAI_RESULT_TYPE => RHAI_RESULT_TYPE_EXPAND.into(), + ty if ty.starts_with(RHAI_RANGE_TYPE) && ty.ends_with('>') => { + let inner = &ty[RHAI_RANGE_TYPE.len()..ty.len() - 1]; + RHAI_RANGE_EXPAND + .replace("{}", Self::format_type(inner, false).trim()) + .into() + } + ty if ty.starts_with(RHAI_INCLUSIVE_RANGE_TYPE) && ty.ends_with('>') => { + let inner = &ty[RHAI_INCLUSIVE_RANGE_TYPE.len()..ty.len() - 1]; + RHAI_INCLUSIVE_RANGE_EXPAND + .replace("{}", Self::format_type(inner, false).trim()) + .into() + } ty if ty.starts_with(RHAI_RESULT_OF_TYPE) && ty.ends_with('>') => { + let inner = &ty[RHAI_RESULT_OF_TYPE.len()..ty.len() - 1]; RHAI_RESULT_OF_TYPE_EXPAND - .replace("{}", ty[RHAI_RESULT_OF_TYPE.len()..ty.len() - 1].trim()) + .replace("{}", Self::format_type(inner, false).trim()) .into() } ty => ty.into(), @@ -116,14 +158,27 @@ impl FuncInfo { pub fn gen_signature(&self) -> String { let mut sig = format!("{}(", self.metadata.name); - let return_type = Self::format_return_type(&self.metadata.return_type); + let return_type = Self::format_type(&self.metadata.return_type, true); if !self.metadata.params_info.is_empty() { let params: StaticVec<_> = self .metadata .params_info .iter() - .map(|s| s.as_str()) + .map(|s| { + let mut seg = s.splitn(2, ':'); + let name = match seg.next().unwrap().trim() { + "" => "_", + s => s, + }; + let result: std::borrow::Cow = match seg.next() { + Some(typ) => { + format!("{}: {}", name, FuncInfo::format_type(typ, false)).into() + } + None => name.into(), + }; + result + }) .collect(); sig.push_str(¶ms.join(", ")); sig.push(')'); diff --git a/src/packages/iter_basic.rs b/src/packages/iter_basic.rs index fe844e70..78ee4519 100644 --- a/src/packages/iter_basic.rs +++ b/src/packages/iter_basic.rs @@ -481,6 +481,12 @@ def_package! { // Register string iterator lib.set_iterator::(); + #[cfg(feature = "metadata")] + let (range_type, range_inclusive_type) = ( + format!("range: Range<{}>", std::any::type_name::()), + format!("range: RangeInclusive<{}>", std::any::type_name::()), + ); + let _hash = lib.set_native_fn("chars", |string, range: ExclusiveRange| { let from = INT::max(range.start, 0); let to = INT::max(range.end, from); @@ -489,7 +495,7 @@ def_package! { #[cfg(feature = "metadata")] lib.update_fn_metadata_with_comments( _hash, - ["string: &str", "range: Range", "Iterator"], + ["string: &str", &range_type, "Iterator"], [ "/// Return an iterator over an exclusive range of characters in the string.", "///", @@ -511,7 +517,7 @@ def_package! { #[cfg(feature = "metadata")] lib.update_fn_metadata_with_comments( _hash, - ["string: &str", "range: RangeInclusive", "Iterator"], + ["string: &str", &range_inclusive_type, "Iterator"], [ "/// Return an iterator over an inclusive range of characters in the string.", "///", @@ -621,7 +627,7 @@ def_package! { #[cfg(feature = "metadata")] lib.update_fn_metadata_with_comments( _hash, - ["value: INT", "range: Range", "Iterator"], + ["value: INT", &range_type, "Iterator"], [ "/// Return an iterator over an exclusive range of bits in the number.", "///", @@ -645,7 +651,7 @@ def_package! { #[cfg(feature = "metadata")] lib.update_fn_metadata_with_comments( _hash, - ["value: INT", "range: RangeInclusive", "Iterator"], + ["value: INT", &range_inclusive_type, "Iterator"], [ "/// Return an iterator over an inclusive range of bits in the number.", "///", @@ -733,7 +739,7 @@ def_package! { #[cfg(feature = "metadata")] lib.update_fn_metadata_with_comments( _hash, - ["value: &mut INT", "range: Range", "Iterator"], + ["value: &mut INT", "Iterator"], [ "/// Return an iterator over all the bits in the number.", "///", diff --git a/src/serde/metadata.rs b/src/serde/metadata.rs index 3ccadfb3..3e1919e0 100644 --- a/src/serde/metadata.rs +++ b/src/serde/metadata.rs @@ -7,7 +7,7 @@ use crate::{calc_fn_hash, Engine, AST}; use serde::{Deserialize, Serialize}; #[cfg(feature = "no_std")] use std::prelude::v1::*; -use std::{cmp::Ordering, collections::BTreeMap, iter::empty}; +use std::{borrow::Cow, cmp::Ordering, collections::BTreeMap, iter::empty}; #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] @@ -54,7 +54,7 @@ struct FnParam<'a> { #[serde(skip_serializing_if = "Option::is_none")] pub name: Option<&'a str>, #[serde(rename = "type", skip_serializing_if = "Option::is_none")] - pub typ: Option<&'a str>, + pub typ: Option>, } #[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)] @@ -125,12 +125,12 @@ impl<'a> From<&'a FuncInfo> for FnMetadata<'a> { "_" => None, s => Some(s), }; - let typ = seg.next().map(&str::trim); + let typ = seg.next().map(|s| FuncInfo::format_type(s, false)); FnParam { name, typ } }) .collect(), _dummy: None, - return_type: FuncInfo::format_return_type(&info.metadata.return_type).into_owned(), + return_type: FuncInfo::format_type(&info.metadata.return_type, true).into_owned(), signature: info.gen_signature(), doc_comments: if info.func.is_script() { #[cfg(feature = "no_function")] diff --git a/src/types/dynamic.rs b/src/types/dynamic.rs index 800ffb2b..d61cd612 100644 --- a/src/types/dynamic.rs +++ b/src/types/dynamic.rs @@ -546,44 +546,66 @@ 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) -> &str { +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 "string"; + return if shorthands { "string" } else { "String" }; } if name == type_name::() { - return "string"; + return if shorthands { + "string" + } else { + "ImmutableString" + }; } if name == type_name::<&str>() { - return "string"; - } - if name == type_name::() { - return "Fn"; + return if shorthands { "string" } else { "&str" }; } #[cfg(feature = "decimal")] if name == type_name::() { - return "decimal"; + 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 "array"; + return if shorthands { "array" } else { "Array" }; } #[cfg(not(feature = "no_index"))] if name == type_name::() { - return "blob"; + return if shorthands { "blob" } else { "Blob" }; } #[cfg(not(feature = "no_object"))] if name == type_name::() { - return "map"; + return if shorthands { "map" } else { "Map" }; } #[cfg(not(feature = "no_std"))] if name == type_name::() { - return "timestamp"; + return if shorthands { "timestamp" } else { "Instant" }; } - if name == type_name::() { - return "range"; + if name == type_name::() || name == "ExclusiveRange" { + return if shorthands { + "range" + } else if cfg!(feature = "only_i32") { + "Range" + } else { + "Range" + }; } - if name == type_name::() { - return "range="; + if name == type_name::() || name == "InclusiveRange" { + return if shorthands { + "range=" + } else if cfg!(feature = "only_i32") { + "RangeInclusive" + } else { + "RangeInclusive" + }; } name