diff --git a/src/api/custom_syntax.rs b/src/api/custom_syntax.rs index b7c1f48b..76b96443 100644 --- a/src/api/custom_syntax.rs +++ b/src/api/custom_syntax.rs @@ -8,7 +8,7 @@ use crate::tokenizer::{is_valid_identifier, Token}; use crate::types::dynamic::Variant; use crate::{ reify, Engine, EvalContext, Identifier, ImmutableString, LexError, Position, RhaiResult, - Shared, StaticVec, + StaticVec, }; use std::ops::Deref; #[cfg(feature = "no_std")] @@ -65,6 +65,15 @@ impl<'a> From<&'a Expr> for Expression<'a> { } impl Expression<'_> { + /// Evaluate this [expression tree][Expression] within an [evaluation context][`EvalContext`]. + /// + /// # WARNING - Low Level API + /// + /// This function is very low level. It evaluates an expression from an [`AST`][crate::AST]. + #[inline(always)] + pub fn eval_with_context(&self, context: &mut EvalContext) -> RhaiResult { + context.eval_expression_tree(self) + } /// Get the value of this expression if it is a variable name or a string constant. /// /// Returns [`None`] also if the constant is not of the specified type. @@ -132,7 +141,7 @@ impl Deref for Expression<'_> { } impl EvalContext<'_, '_, '_, '_, '_, '_, '_, '_> { - /// Evaluate an [expression tree][Expression]. + /// Evaluate an [expression tree][Expression] within this [evaluation context][`EvalContext`]. /// /// # WARNING - Low Level API /// @@ -165,7 +174,7 @@ pub struct CustomSyntax { /// symbols parsed so far. pub parse: Box, /// Custom syntax implementation function. - pub func: Shared, + pub func: Box, /// Any variables added/removed in the scope? pub scope_may_be_changed: bool, } @@ -356,7 +365,7 @@ impl Engine { key.into(), CustomSyntax { parse: Box::new(parse), - func: (Box::new(func) as Box).into(), + func: Box::new(func), scope_may_be_changed, } .into(), diff --git a/src/api/json.rs b/src/api/json.rs index 856e25f4..f8a8c2ce 100644 --- a/src/api/json.rs +++ b/src/api/json.rs @@ -119,8 +119,8 @@ impl Engine { }, ); - let scope = &Scope::new(); - let mut state = ParseState::new(self, scope, tokenizer_control); + let scope = Scope::new(); + let mut state = ParseState::new(self, &scope, tokenizer_control); let ast = self.parse_global_expr( &mut stream.peekable(), diff --git a/src/engine.rs b/src/engine.rs index 8b0975d4..da83207e 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -112,7 +112,7 @@ pub struct Engine { /// A map containing custom keywords and precedence to recognize. pub(crate) custom_keywords: BTreeMap>, /// Custom syntax. - pub(crate) custom_syntax: BTreeMap>, + pub(crate) custom_syntax: BTreeMap, /// Callback closure for filtering variable definition. pub(crate) def_var_filter: Option>, /// Callback closure for resolving variable access. @@ -155,7 +155,14 @@ impl fmt::Debug for Engine { f.field("disabled_symbols", &self.disabled_symbols) .field("custom_keywords", &self.custom_keywords) - .field("custom_syntax", &(!self.custom_syntax.is_empty())) + .field( + "custom_syntax", + &self + .custom_syntax + .keys() + .map(|s| s.as_str()) + .collect::(), + ) .field("def_var_filter", &self.def_var_filter.is_some()) .field("resolve_var", &self.resolve_var.is_some()) .field("token_mapper", &self.token_mapper.is_some()); diff --git a/src/eval/cache.rs b/src/eval/cache.rs index 64c9e0fb..8b552280 100644 --- a/src/eval/cache.rs +++ b/src/eval/cache.rs @@ -13,8 +13,7 @@ pub struct FnResolutionCacheEntry { /// Function. pub func: CallableFunction, /// Optional source. - /// No source if the string is empty. - pub source: Identifier, + pub source: Option>, } /// _(internals)_ A function resolution cache. @@ -22,7 +21,7 @@ pub struct FnResolutionCacheEntry { /// /// [`FnResolutionCacheEntry`] is [`Box`]ed in order to pack as many entries inside a single B-Tree /// level as possible. -pub type FnResolutionCache = BTreeMap>>; +pub type FnResolutionCache = BTreeMap>; /// _(internals)_ A type containing system-wide caches. /// Exported under the `internals` feature only. diff --git a/src/eval/eval_context.rs b/src/eval/eval_context.rs index 4e25abc9..ed93f8ff 100644 --- a/src/eval/eval_context.rs +++ b/src/eval/eval_context.rs @@ -7,13 +7,13 @@ use std::prelude::v1::*; /// Context of a script evaluation process. #[derive(Debug)] -pub struct EvalContext<'a, 's, 'ps, 'm, 'pm, 'c, 't, 'pt> { +pub struct EvalContext<'a, 's, 'ps, 'g, 'pg, 'c, 't, 'pt> { /// The current [`Engine`]. pub(crate) engine: &'a Engine, /// The current [`Scope`]. pub(crate) scope: &'s mut Scope<'ps>, /// The current [`GlobalRuntimeState`]. - pub(crate) global: &'m mut GlobalRuntimeState<'pm>, + pub(crate) global: &'g mut GlobalRuntimeState<'pg>, /// The current [caches][Caches], if available. pub(crate) caches: Option<&'c mut Caches>, /// The current stack of imported [modules][Module]. @@ -24,7 +24,7 @@ pub struct EvalContext<'a, 's, 'ps, 'm, 'pm, 'c, 't, 'pt> { pub(crate) level: usize, } -impl<'s, 'ps, 'm, 'pm, 'pt> EvalContext<'_, 's, 'ps, 'm, 'pm, '_, '_, 'pt> { +impl<'s, 'ps, 'g, 'pg, 'pt> EvalContext<'_, 's, 'ps, 'g, 'pg, '_, '_, 'pt> { /// The current [`Engine`]. #[inline(always)] #[must_use] @@ -85,7 +85,7 @@ impl<'s, 'ps, 'm, 'pm, 'pt> EvalContext<'_, 's, 'ps, 'm, 'pm, '_, '_, 'pt> { #[cfg(feature = "internals")] #[inline(always)] #[must_use] - pub fn global_runtime_state_mut(&mut self) -> &mut &'m mut GlobalRuntimeState<'pm> { + pub fn global_runtime_state_mut(&mut self) -> &mut &'g mut GlobalRuntimeState<'pg> { &mut self.global } /// Get an iterator over the namespaces containing definition of all script-defined functions. diff --git a/src/func/call.rs b/src/func/call.rs index caec732a..cfeebacb 100644 --- a/src/func/call.rs +++ b/src/func/call.rs @@ -214,14 +214,14 @@ impl Engine { .find_map(|&m| { m.get_fn(hash).cloned().map(|func| FnResolutionCacheEntry { func, - source: m.id_raw().clone(), + source: m.id().map(|s| Box::new(s.into())), }) }) .or_else(|| { self.global_modules.iter().find_map(|m| { m.get_fn(hash).cloned().map(|func| FnResolutionCacheEntry { func, - source: m.id_raw().clone(), + source: m.id().map(|s| Box::new(s.into())), }) }) }); @@ -232,8 +232,7 @@ impl Engine { _global.get_qualified_fn(hash).map(|(func, source)| { FnResolutionCacheEntry { func: func.clone(), - source: source - .map_or_else(|| Identifier::new_const(), Into::into), + source: source.map(|s| Box::new(s.into())), } }) }) @@ -242,7 +241,7 @@ impl Engine { m.get_qualified_fn(hash).cloned().map(|func| { FnResolutionCacheEntry { func, - source: m.id_raw().clone(), + source: m.id().map(|s| Box::new(s.into())), } }) }) @@ -250,7 +249,7 @@ impl Engine { match func { // Specific version found - Some(f) => return Some(Box::new(f)), + Some(f) => return Some(f), // Stop when all permutations are exhausted None if bitmask >= max_bitmask => { @@ -265,7 +264,7 @@ impl Engine { func: CallableFunction::from_method( Box::new(f) as Box ), - source: Identifier::new_const(), + source: None, } }) } else { @@ -276,10 +275,9 @@ impl Engine { func: CallableFunction::from_method( Box::new(f) as Box ), - source: Identifier::new_const(), + source: None, }) } - .map(Box::new) }); } @@ -308,7 +306,7 @@ impl Engine { } }); - result.as_ref().map(Box::as_ref) + result.as_ref() } /// # Main Entry-Point @@ -370,9 +368,10 @@ impl Engine { backup.change_first_arg_to_copy(args); } - let source = match (source.as_str(), parent_source.as_str()) { - ("", "") => None, - ("", s) | (s, ..) => Some(s), + let source = match (source, parent_source.as_str()) { + (None, "") => None, + (None, s) => Some(s), + (Some(s), ..) => Some(s.as_str()), }; #[cfg(feature = "debugging")] @@ -626,7 +625,7 @@ impl Engine { // Script-defined function call? #[cfg(not(feature = "no_function"))] - if let Some(FnResolutionCacheEntry { func, mut source }) = self + if let Some(FnResolutionCacheEntry { func, ref source }) = self .resolve_fn( global, caches, @@ -657,7 +656,13 @@ impl Engine { } }; - mem::swap(&mut global.source, &mut source); + let orig_source = mem::replace( + &mut global.source, + source + .as_ref() + .map(|s| (**s).clone()) + .unwrap_or(Identifier::new_const()), + ); let result = if _is_method_call { // Method call of script function - map first argument to `this` @@ -695,7 +700,7 @@ impl Engine { }; // Restore the original source - mem::swap(&mut global.source, &mut source); + global.source = orig_source; return Ok((result?, false)); } @@ -757,7 +762,7 @@ impl Engine { // Recalculate hashes let new_hash = calc_fn_hash(fn_name, args_len).into(); // Arguments are passed as-is, adding the curried arguments - let mut curry = FnArgsVec::with_capacity(fn_ptr.num_curried()); + let mut curry = FnArgsVec::with_capacity(fn_ptr.curry().len()); curry.extend(fn_ptr.curry().iter().cloned()); let mut args = FnArgsVec::with_capacity(curry.len() + call_args.len()); args.extend(curry.iter_mut()); @@ -792,7 +797,7 @@ impl Engine { calc_fn_hash(fn_name, args_len + 1), ); // Replace the first argument with the object pointer, adding the curried arguments - let mut curry = FnArgsVec::with_capacity(fn_ptr.num_curried()); + let mut curry = FnArgsVec::with_capacity(fn_ptr.curry().len()); curry.extend(fn_ptr.curry().iter().cloned()); let mut args = FnArgsVec::with_capacity(curry.len() + call_args.len() + 1); args.push(target.as_mut()); diff --git a/src/lib.rs b/src/lib.rs index f10e2b20..f4a7bfff 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -44,7 +44,7 @@ //! # #[cfg(not(target_family = "wasm"))] //! # //! // Evaluate the script, expecting a 'bool' result -//! let result = engine.eval_file::("my_script.rhai".into())?; +//! let result: bool = engine.eval_file("my_script.rhai".into())?; //! //! assert_eq!(result, true); //! diff --git a/src/module/mod.rs b/src/module/mod.rs index 5ad8e48e..c3b68758 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -81,7 +81,7 @@ impl Ord for FnMetadata { #[derive(Debug, Clone)] pub struct FuncInfo { /// Function instance. - pub func: Shared, + pub func: CallableFunction, /// Parameter types (if applicable). pub param_types: StaticVec, /// Function metadata. @@ -246,7 +246,7 @@ pub struct Module { functions: BTreeMap>, /// Flattened collection of all external Rust functions, native or scripted. /// including those in sub-modules. - all_functions: BTreeMap>, + all_functions: BTreeMap, /// Iterator functions, keyed by the type producing the iterator. type_iterators: BTreeMap>, /// Flattened collection of iterator functions, including those in sub-modules. @@ -1452,7 +1452,7 @@ impl Module { #[must_use] pub(crate) fn get_fn(&self, hash_fn: u64) -> Option<&CallableFunction> { if !self.functions.is_empty() { - self.functions.get(&hash_fn).map(|f| f.func.as_ref()) + self.functions.get(&hash_fn).map(|f| &f.func) } else { None } @@ -1479,9 +1479,7 @@ impl Module { #[must_use] pub(crate) fn get_qualified_fn(&self, hash_qualified_fn: u64) -> Option<&CallableFunction> { if !self.all_functions.is_empty() { - self.all_functions - .get(&hash_qualified_fn) - .map(|f| f.as_ref()) + self.all_functions.get(&hash_qualified_fn) } else { None } @@ -1932,7 +1930,7 @@ impl Module { module: &'a Module, path: &mut Vec<&'a str>, variables: &mut BTreeMap, - functions: &mut BTreeMap>, + functions: &mut BTreeMap, type_iterators: &mut BTreeMap>, ) -> bool { let mut contains_indexed_global_functions = false;