1use crate::packages::iter_basic::{BitRange, CharsStream, StepRange};
3use crate::parser::{ParseResult, ParseState};
4use crate::tokenizer::TokenStream;
5use crate::{
6 Engine, ExclusiveRange, FnPtr, ImmutableString, InclusiveRange, Position, RhaiError,
7 SmartString, ERR,
8};
9use std::any::type_name;
10#[cfg(feature = "no_std")]
11use std::prelude::v1::*;
12
13#[inline]
15#[must_use]
16pub fn map_std_type_name(name: &str, shorthands: bool) -> &str {
17 let name = name.trim();
18
19 match name {
20 "INT" => return type_name::<crate::INT>(),
21 #[cfg(not(feature = "no_float"))]
22 "FLOAT" => return type_name::<crate::FLOAT>(),
23 _ => (),
24 }
25
26 if name == type_name::<String>() {
27 return if shorthands { "string" } else { "String" };
28 }
29 if name == type_name::<ImmutableString>() || name == "ImmutableString" {
30 return if shorthands {
31 "string"
32 } else {
33 "ImmutableString"
34 };
35 }
36 if name == type_name::<&str>() {
37 return if shorthands { "string" } else { "&str" };
38 }
39 #[cfg(feature = "decimal")]
40 if name == type_name::<rust_decimal::Decimal>() {
41 return if shorthands { "decimal" } else { "Decimal" };
42 }
43 if name == type_name::<FnPtr>() || name == "FnPtr" {
44 return if shorthands { "Fn" } else { "FnPtr" };
45 }
46 #[cfg(not(feature = "no_index"))]
47 if name == type_name::<crate::Array>() || name == "Array" {
48 return if shorthands { "array" } else { "Array" };
49 }
50 #[cfg(not(feature = "no_index"))]
51 if name == type_name::<crate::Blob>() || name == "Blob" {
52 return if shorthands { "blob" } else { "Blob" };
53 }
54 #[cfg(not(feature = "no_object"))]
55 if name == type_name::<crate::Map>() || name == "Map" {
56 return if shorthands { "map" } else { "Map" };
57 }
58 #[cfg(not(feature = "no_time"))]
59 if name == type_name::<crate::Instant>() || name == "Instant" {
60 return if shorthands { "timestamp" } else { "Instant" };
61 }
62 if name == type_name::<ExclusiveRange>() || name == "ExclusiveRange" {
63 return if shorthands {
64 "range"
65 } else if cfg!(feature = "only_i32") {
66 "Range<i32>"
67 } else {
68 "Range<i64>"
69 };
70 }
71 if name == type_name::<InclusiveRange>() || name == "InclusiveRange" {
72 return if shorthands {
73 "range="
74 } else if cfg!(feature = "only_i32") {
75 "RangeInclusive<i32>"
76 } else {
77 "RangeInclusive<i64>"
78 };
79 }
80 if name == type_name::<BitRange>() {
81 return if shorthands { "range" } else { "BitRange" };
82 }
83 if name == type_name::<CharsStream>() {
84 return if shorthands { "range" } else { "CharStream" };
85 }
86
87 let step_range_name = type_name::<StepRange<u8>>();
88 let step_range_name = &step_range_name[..step_range_name.len() - 3];
89
90 if name.starts_with(step_range_name) && name.ends_with('>') {
91 return if shorthands {
92 "range"
93 } else {
94 let step_range_name = step_range_name.split("::").last().unwrap();
95 &step_range_name[..step_range_name.len() - 1]
96 };
97 }
98
99 #[cfg(not(feature = "no_float"))]
100 if name == type_name::<crate::packages::iter_basic::StepRange<crate::FLOAT>>() {
101 return if shorthands {
102 "range"
103 } else {
104 "StepFloatRange"
105 };
106 }
107 #[cfg(feature = "decimal")]
108 if name == type_name::<crate::packages::iter_basic::StepRange<rust_decimal::Decimal>>() {
109 return if shorthands {
110 "range"
111 } else {
112 "StepDecimalRange"
113 };
114 }
115
116 name.strip_prefix("rhai::")
117 .map_or(name, |s| map_std_type_name(s, shorthands))
118}
119
120#[cfg(feature = "metadata")]
128pub fn format_param_type_for_display(typ: &str, is_return_type: bool) -> std::borrow::Cow<'_, str> {
129 const RESULT_TYPE: &str = "Result<";
130 const ERROR_TYPE: &str = ",Box<EvalAltResult>>";
131 const RHAI_RESULT_TYPE: &str = "RhaiResult";
132 const RHAI_RESULT_TYPE_EXPAND: &str = "Result<Dynamic, Box<EvalAltResult>>";
133 const RHAI_RESULT_OF_TYPE: &str = "RhaiResultOf<";
134 const RHAI_RESULT_OF_TYPE_EXPAND: &str = "Result<{}, Box<EvalAltResult>>";
135 const RHAI_RANGE: &str = "ExclusiveRange";
136 const RHAI_RANGE_TYPE: &str = "Range<";
137 const RHAI_RANGE_EXPAND: &str = "Range<{}>";
138 const RHAI_INCLUSIVE_RANGE: &str = "InclusiveRange";
139 const RHAI_INCLUSIVE_RANGE_TYPE: &str = "RangeInclusive<";
140 const RHAI_INCLUSIVE_RANGE_EXPAND: &str = "RangeInclusive<{}>";
141
142 let typ = typ.trim();
143
144 if let Some(x) = typ.strip_prefix("rhai::") {
145 return format_param_type_for_display(x, is_return_type);
146 } else if let Some(x) = typ.strip_prefix("&mut ") {
147 let r = format_param_type_for_display(x, false);
148 return if r == x {
149 typ.into()
150 } else {
151 format!("&mut {r}").into()
152 };
153 } else if typ.contains(' ') {
154 let typ = typ.replace(' ', "");
155 let r = format_param_type_for_display(&typ, is_return_type);
156 return r.into_owned().into();
157 }
158
159 match typ {
160 "" | "()" if is_return_type => "".into(),
161 "INT" => std::any::type_name::<crate::INT>().into(),
162 #[cfg(not(feature = "no_float"))]
163 "FLOAT" => std::any::type_name::<crate::FLOAT>().into(),
164 RHAI_RANGE => RHAI_RANGE_EXPAND
165 .replace("{}", std::any::type_name::<crate::INT>())
166 .into(),
167 RHAI_INCLUSIVE_RANGE => RHAI_INCLUSIVE_RANGE_EXPAND
168 .replace("{}", std::any::type_name::<crate::INT>())
169 .into(),
170 RHAI_RESULT_TYPE => RHAI_RESULT_TYPE_EXPAND.into(),
171 ty if ty.starts_with(RHAI_RANGE_TYPE) && ty.ends_with('>') => {
172 let inner = &ty[RHAI_RANGE_TYPE.len()..ty.len() - 1];
173 RHAI_RANGE_EXPAND
174 .replace("{}", format_param_type_for_display(inner, false).trim())
175 .into()
176 }
177 ty if ty.starts_with(RHAI_INCLUSIVE_RANGE_TYPE) && ty.ends_with('>') => {
178 let inner = &ty[RHAI_INCLUSIVE_RANGE_TYPE.len()..ty.len() - 1];
179 RHAI_INCLUSIVE_RANGE_EXPAND
180 .replace("{}", format_param_type_for_display(inner, false).trim())
181 .into()
182 }
183 ty if ty.starts_with(RHAI_RESULT_OF_TYPE) && ty.ends_with('>') => {
184 let inner = &ty[RHAI_RESULT_OF_TYPE.len()..ty.len() - 1];
185 RHAI_RESULT_OF_TYPE_EXPAND
186 .replace("{}", format_param_type_for_display(inner, false).trim())
187 .into()
188 }
189 ty if ty.starts_with(RESULT_TYPE) && ty.ends_with(ERROR_TYPE) => {
190 let inner = &ty[RESULT_TYPE.len()..ty.len() - ERROR_TYPE.len()];
191 RHAI_RESULT_OF_TYPE_EXPAND
192 .replace("{}", format_param_type_for_display(inner, false).trim())
193 .into()
194 }
195 ty => ty.into(),
196 }
197}
198
199impl Engine {
200 #[inline]
205 #[must_use]
206 pub fn map_type_name<'a>(&'a self, name: &'a str) -> &'a str {
207 self.global_modules
208 .iter()
209 .find_map(|m| m.get_custom_type_display_by_name(name))
210 .or_else(|| {
211 #[cfg(not(feature = "no_module"))]
212 return self
213 .global_sub_modules
214 .values()
215 .find_map(|m| m.get_custom_type_display_by_name(name));
216
217 #[cfg(feature = "no_module")]
218 return None;
219 })
220 .unwrap_or_else(|| map_std_type_name(name, true))
221 }
222
223 #[cfg(feature = "metadata")]
230 #[inline]
231 #[must_use]
232 pub(crate) fn format_param_type<'a>(&'a self, name: &'a str) -> std::borrow::Cow<'a, str> {
233 if let Some(x) = name.strip_prefix("&mut ") {
234 return match self.format_param_type(x) {
235 r if r == x => name.into(),
236 r => format!("&mut {r}").into(),
237 };
238 }
239
240 self.map_type_name(name).into()
241 }
242
243 #[cold]
245 #[inline(never)]
246 #[must_use]
247 pub(crate) fn make_type_mismatch_err<T>(&self, typ: &str, pos: Position) -> RhaiError {
248 ERR::ErrorMismatchDataType(self.map_type_name(type_name::<T>()).into(), typ.into(), pos)
249 .into()
250 }
251
252 #[inline]
261 pub fn compact_script(&self, script: impl AsRef<str>) -> ParseResult<String> {
262 let scripts = [script];
263 let (mut stream, tc) = self.lex(&scripts);
264
265 tc.borrow_mut().compressed = Some(String::new());
266 stream.state.last_token = Some(SmartString::new_const());
267
268 let input = &mut TokenStream::new(stream);
269 let lib = &mut <_>::default();
270 let state = ParseState::new(None, input, tc.clone(), lib);
271
272 let mut _ast = self.parse(
273 state,
274 #[cfg(not(feature = "no_optimize"))]
275 crate::OptimizationLevel::None,
276 )?;
277
278 let guard = tc.borrow();
279 Ok(guard.compressed.as_ref().unwrap().into())
280 }
281}