use crate::packages::iter_basic::{BitRange, CharsStream, StepRange};
use crate::parser::{ParseResult, ParseState};
use crate::types::StringsInterner;
use crate::{
Engine, ExclusiveRange, FnPtr, ImmutableString, InclusiveRange, Position, RhaiError,
SmartString, ERR,
};
use std::any::type_name;
#[cfg(feature = "no_std")]
use std::prelude::v1::*;
#[inline]
#[must_use]
fn map_std_type_name(name: &str, shorthands: bool) -> &str {
let name = name.trim();
if name == type_name::<String>() {
return if shorthands { "string" } else { "String" };
}
if name == type_name::<ImmutableString>() || 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::<rust_decimal::Decimal>() {
return if shorthands { "decimal" } else { "Decimal" };
}
if name == type_name::<FnPtr>() || name == "FnPtr" {
return if shorthands { "Fn" } else { "FnPtr" };
}
#[cfg(not(feature = "no_index"))]
if name == type_name::<crate::Array>() || name == "Array" {
return if shorthands { "array" } else { "Array" };
}
#[cfg(not(feature = "no_index"))]
if name == type_name::<crate::Blob>() || name == "Blob" {
return if shorthands { "blob" } else { "Blob" };
}
#[cfg(not(feature = "no_object"))]
if name == type_name::<crate::Map>() || name == "Map" {
return if shorthands { "map" } else { "Map" };
}
#[cfg(not(feature = "no_time"))]
if name == type_name::<crate::Instant>() || name == "Instant" {
return if shorthands { "timestamp" } else { "Instant" };
}
if name == type_name::<ExclusiveRange>() || name == "ExclusiveRange" {
return if shorthands {
"range"
} else if cfg!(feature = "only_i32") {
"Range<i32>"
} else {
"Range<i64>"
};
}
if name == type_name::<InclusiveRange>() || name == "InclusiveRange" {
return if shorthands {
"range="
} else if cfg!(feature = "only_i32") {
"RangeInclusive<i32>"
} else {
"RangeInclusive<i64>"
};
}
if name == type_name::<BitRange>() {
return if shorthands { "range" } else { "BitRange" };
}
if name == type_name::<CharsStream>() {
return if shorthands { "range" } else { "CharStream" };
}
let step_range_name = type_name::<StepRange<u8>>();
let step_range_name = &step_range_name[..step_range_name.len() - 3];
if name.starts_with(step_range_name) && name.ends_with('>') {
return if shorthands {
"range"
} else {
let step_range_name = step_range_name.split("::").last().unwrap();
&step_range_name[..step_range_name.len() - 1]
};
}
#[cfg(not(feature = "no_float"))]
if name == type_name::<crate::packages::iter_basic::StepRange<crate::FLOAT>>() {
return if shorthands {
"range"
} else {
"StepFloatRange"
};
}
#[cfg(feature = "decimal")]
if name == type_name::<crate::packages::iter_basic::StepRange<rust_decimal::Decimal>>() {
return if shorthands {
"range"
} else {
"StepDecimalRange"
};
}
name.strip_prefix("rhai::")
.map_or(name, |s| map_std_type_name(s, shorthands))
}
#[cfg(feature = "metadata")]
pub fn format_type(typ: &str, is_return_type: bool) -> std::borrow::Cow<str> {
const RESULT_TYPE: &str = "Result<";
const ERROR_TYPE: &str = ",Box<EvalAltResult>>";
const RHAI_RESULT_TYPE: &str = "RhaiResult";
const RHAI_RESULT_TYPE_EXPAND: &str = "Result<Dynamic, Box<EvalAltResult>>";
const RHAI_RESULT_OF_TYPE: &str = "RhaiResultOf<";
const RHAI_RESULT_OF_TYPE_EXPAND: &str = "Result<{}, Box<EvalAltResult>>";
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 let Some(x) = typ.strip_prefix("rhai::") {
return format_type(x, is_return_type);
} else if let Some(x) = typ.strip_prefix("&mut ") {
let r = format_type(x, false);
return if r == x {
typ.into()
} else {
format!("&mut {r}").into()
};
} else if typ.contains(' ') {
let typ = typ.replace(' ', "");
let r = format_type(&typ, is_return_type);
return r.into_owned().into();
}
match typ {
"" | "()" if is_return_type => "".into(),
"INT" => std::any::type_name::<crate::INT>().into(),
#[cfg(not(feature = "no_float"))]
"FLOAT" => std::any::type_name::<crate::FLOAT>().into(),
RHAI_RANGE => RHAI_RANGE_EXPAND
.replace("{}", std::any::type_name::<crate::INT>())
.into(),
RHAI_INCLUSIVE_RANGE => RHAI_INCLUSIVE_RANGE_EXPAND
.replace("{}", std::any::type_name::<crate::INT>())
.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("{}", 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("{}", 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("{}", format_type(inner, false).trim())
.into()
}
ty if ty.starts_with(RESULT_TYPE) && ty.ends_with(ERROR_TYPE) => {
let inner = &ty[RESULT_TYPE.len()..ty.len() - ERROR_TYPE.len()];
RHAI_RESULT_OF_TYPE_EXPAND
.replace("{}", format_type(inner, false).trim())
.into()
}
ty => ty.into(),
}
}
impl Engine {
#[inline]
#[must_use]
pub fn map_type_name<'a>(&'a self, name: &'a str) -> &'a str {
self.global_modules
.iter()
.find_map(|m| m.get_custom_type(name))
.or_else(|| {
#[cfg(not(feature = "no_module"))]
return self
.global_sub_modules
.as_ref()
.into_iter()
.flatten()
.find_map(|(_, m)| m.get_custom_type(name));
#[cfg(feature = "no_module")]
return None;
})
.unwrap_or_else(|| map_std_type_name(name, true))
}
#[cfg(feature = "metadata")]
#[inline]
#[must_use]
pub(crate) fn format_type_name<'a>(&'a self, name: &'a str) -> std::borrow::Cow<'a, str> {
if let Some(x) = name.strip_prefix("&mut ") {
let r = self.format_type_name(x);
return if x == r {
name.into()
} else {
format!("&mut {r}").into()
};
}
self.global_modules
.iter()
.find_map(|m| m.get_custom_type(name))
.or_else(|| {
#[cfg(not(feature = "no_module"))]
return self
.global_sub_modules
.as_ref()
.into_iter()
.flatten()
.find_map(|(_, m)| m.get_custom_type(name));
#[cfg(feature = "no_module")]
return None;
})
.unwrap_or_else(|| match name {
"INT" => type_name::<crate::INT>(),
#[cfg(not(feature = "no_float"))]
"FLOAT" => type_name::<crate::FLOAT>(),
_ => map_std_type_name(name, false),
})
.into()
}
#[cold]
#[inline(never)]
#[must_use]
pub(crate) fn make_type_mismatch_err<T>(&self, typ: &str, pos: Position) -> RhaiError {
let t = self.map_type_name(type_name::<T>()).into();
ERR::ErrorMismatchDataType(t, typ.into(), pos).into()
}
#[inline]
pub fn compact_script(&self, script: impl AsRef<str>) -> ParseResult<String> {
let scripts = [script];
let (mut stream, tc) = self.lex_raw(&scripts, self.token_mapper.as_deref());
tc.borrow_mut().compressed = Some(String::new());
stream.state.last_token = Some(SmartString::new_const());
let mut interner = StringsInterner::new();
let mut state = ParseState::new(None, &mut interner, tc);
let mut _ast = self.parse(
stream.peekable(),
&mut state,
#[cfg(not(feature = "no_optimize"))]
crate::OptimizationLevel::None,
#[cfg(feature = "no_optimize")]
(),
)?;
let tc = state.tokenizer_control.borrow();
Ok(tc.compressed.as_ref().unwrap().into())
}
}