diff --git a/CHANGELOG.md b/CHANGELOG.md index 05033bb4..a5abea2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ Breaking changes * `Module::update_fn_metadata` input parameter is changed. * Function keywords (e.g. `type_of`, `eval`, `Fn`) can no longer be overloaded. It is more trouble than worth. To disable these keywords, use `Engine::disable_symbol`. * `is_def_var` and `is_def_fn` are now reserved keywords. +* `Engine::id` field is removed. Enhancements ------------ diff --git a/src/engine.rs b/src/engine.rs index 8a29067b..df58d80d 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -525,18 +525,6 @@ impl State { pub fn is_global(&self) -> bool { self.scope_level == 0 } - /// Get the current functions resolution cache. - pub fn fn_resolution_cache( - &self, - ) -> Option< - &HashMap< - NonZeroU64, - Option<(CallableFunction, Option)>, - StraightHasherBuilder, - >, - > { - self.fn_resolution_caches.last() - } /// Get a mutable reference to the current functions resolution cache. pub fn fn_resolution_cache_mut( &mut self, @@ -617,17 +605,17 @@ pub struct Limits { /// Context of a script evaluation process. #[derive(Debug)] -pub struct EvalContext<'e, 'x, 'px, 'a, 's, 'm, 't, 'pt> { - pub(crate) engine: &'e Engine, +pub struct EvalContext<'a, 'x, 'px, 'm, 's, 't, 'pt> { + pub(crate) engine: &'a Engine, pub(crate) scope: &'x mut Scope<'px>, - pub(crate) mods: &'a mut Imports, + pub(crate) mods: &'m mut Imports, pub(crate) state: &'s mut State, - pub(crate) lib: &'m [&'m Module], + pub(crate) lib: &'a [&'a Module], pub(crate) this_ptr: &'t mut Option<&'pt mut Dynamic>, pub(crate) level: usize, } -impl<'e, 'x, 'px, 'a, 's, 'm, 't, 'pt> EvalContext<'e, 'x, 'px, 'a, 's, 'm, 't, 'pt> { +impl<'x, 'px> EvalContext<'_, 'x, 'px, '_, '_, '_, '_> { /// The current [`Engine`]. #[inline(always)] pub fn engine(&self) -> &Engine { @@ -710,9 +698,6 @@ impl<'e, 'x, 'px, 'a, 's, 'm, 't, 'pt> EvalContext<'e, 'x, 'px, 'a, 's, 'm, 't, /// # } /// ``` pub struct Engine { - /// A unique ID identifying this scripting [`Engine`]. - pub id: String, - /// A module containing all functions directly loaded into the Engine. pub(crate) global_namespace: Module, /// A collection of all modules loaded into the global namespace of the Engine. @@ -757,11 +742,7 @@ pub struct Engine { impl fmt::Debug for Engine { #[inline(always)] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if !self.id.is_empty() { - write!(f, "Engine({})", self.id) - } else { - f.write_str("Engine") - } + f.write_str("Engine") } } @@ -819,8 +800,6 @@ impl Engine { pub fn new() -> Self { // Create the new scripting Engine let mut engine = Self { - id: Default::default(), - global_namespace: Default::default(), global_modules: Default::default(), global_sub_modules: Default::default(), @@ -886,8 +865,6 @@ impl Engine { #[inline] pub fn new_raw() -> Self { Self { - id: Default::default(), - global_namespace: Default::default(), global_modules: Default::default(), global_sub_modules: Default::default(), @@ -934,14 +911,13 @@ impl Engine { } /// Search for a module within an imports stack. - /// [`Position`] in [`EvalAltResult`] is [`NONE`][Position::NONE] and must be set afterwards. - pub fn search_imports( + pub(crate) fn search_imports( &self, mods: &Imports, state: &mut State, namespace: &NamespaceRef, - ) -> Result, Box> { - let Ident { name: root, pos } = &namespace[0]; + ) -> Option> { + let root = &namespace[0].name; // Qualified - check if the root module is directly indexed let index = if state.always_search { @@ -950,15 +926,14 @@ impl Engine { namespace.index() }; - Ok(if let Some(index) = index { + if let Some(index) = index { let offset = mods.len() - index.get(); - mods.get(offset).expect("invalid index in Imports") + Some(mods.get(offset).expect("invalid index in Imports")) } else { mods.find(root) .map(|n| mods.get(n).expect("invalid index in Imports")) .or_else(|| self.global_sub_modules.get(root).cloned()) - .ok_or_else(|| EvalAltResult::ErrorModuleNotFound(root.to_string(), *pos))? - }) + } } /// Search for a variable within the scope or within imports, @@ -976,7 +951,12 @@ impl Engine { Expr::Variable(v) => match v.as_ref() { // Qualified variable (_, Some((hash_var, modules)), Ident { name, pos }) => { - let module = self.search_imports(mods, state, modules)?; + let module = self.search_imports(mods, state, modules).ok_or_else(|| { + EvalAltResult::ErrorModuleNotFound( + modules[0].name.to_string(), + modules[0].pos, + ) + })?; let target = module.get_qualified_var(*hash_var).map_err(|mut err| { match *err { EvalAltResult::ErrorVariableNotFound(ref mut err_name, _) => { @@ -1068,7 +1048,7 @@ impl Engine { } /// Chain-evaluate a dot/index chain. - /// [`Position`] in [`EvalAltResult`] is [`None`][Position::None] and must be set afterwards. + /// [`Position`] in [`EvalAltResult`] is [`NONE`][Position::NONE] and must be set afterwards. #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] fn eval_dot_index_chain_helper( &self, diff --git a/src/engine_api.rs b/src/engine_api.rs index 6d12353f..ee804636 100644 --- a/src/engine_api.rs +++ b/src/engine_api.rs @@ -1028,7 +1028,7 @@ impl Engine { scripts: &[&str], optimization_level: OptimizationLevel, ) -> Result { - let stream = self.lex(scripts); + let stream = self.lex_raw(scripts, None); self.parse(&mut stream.peekable(), scope, optimization_level) } /// Read the contents of a file into a string. @@ -1190,9 +1190,9 @@ impl Engine { .into()); }; - let stream = self.lex_with_map( + let stream = self.lex_raw( &scripts, - if has_null { + Some(if has_null { |token| match token { // If `null` is present, make sure `null` is treated as a variable Token::Reserved(s) if s == "null" => Token::Identifier(s), @@ -1200,7 +1200,7 @@ impl Engine { } } else { |t| t - }, + }), ); let ast = @@ -1283,7 +1283,7 @@ impl Engine { script: &str, ) -> Result { let scripts = [script]; - let stream = self.lex(&scripts); + let stream = self.lex_raw(&scripts, None); let mut peekable = stream.peekable(); self.parse_global_expr(&mut peekable, scope, self.optimization_level) @@ -1444,7 +1444,7 @@ impl Engine { script: &str, ) -> Result> { let scripts = [script]; - let stream = self.lex(&scripts); + let stream = self.lex_raw(&scripts, None); // No need to optimize a lone expression let ast = self.parse_global_expr(&mut stream.peekable(), scope, OptimizationLevel::None)?; @@ -1585,7 +1585,7 @@ impl Engine { script: &str, ) -> Result<(), Box> { let scripts = [script]; - let stream = self.lex(&scripts); + let stream = self.lex_raw(&scripts, None); let ast = self.parse(&mut stream.peekable(), scope, self.optimization_level)?; self.consume_ast_with_scope(scope, &ast) } diff --git a/src/engine_settings.rs b/src/engine_settings.rs index 84b57184..166f41f0 100644 --- a/src/engine_settings.rs +++ b/src/engine_settings.rs @@ -203,7 +203,7 @@ impl Engine { /// # Examples /// /// The following will raise an error during parsing because the `if` keyword is disabled - /// and is recognized as a variable name! + /// and is recognized as a reserved symbol! /// /// ```rust,should_panic /// # fn main() -> Result<(), rhai::ParseError> { @@ -214,7 +214,7 @@ impl Engine { /// engine.disable_symbol("if"); // disable the 'if' keyword /// /// engine.compile("let x = if true { 42 } else { 0 };")?; - /// // ^ 'if' is rejected as a reserved keyword + /// // ^ 'if' is rejected as a reserved symbol /// # Ok(()) /// # } /// ``` diff --git a/src/fn_call.rs b/src/fn_call.rs index 20b09bf4..a9e4c009 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -1357,7 +1357,9 @@ impl Engine { } } - let module = self.search_imports(mods, state, namespace)?; + let module = self.search_imports(mods, state, namespace).ok_or_else(|| { + EvalAltResult::ErrorModuleNotFound(namespace[0].name.to_string(), namespace[0].pos) + })?; // First search in script-defined functions (can override built-in) let func = match module.get_qualified_fn(hash_script) { diff --git a/src/fn_native.rs b/src/fn_native.rs index 728c8765..11801050 100644 --- a/src/fn_native.rs +++ b/src/fn_native.rs @@ -55,20 +55,19 @@ pub type Locked = crate::stdlib::sync::RwLock; /// Context of a native Rust function call. #[derive(Debug, Copy, Clone)] -pub struct NativeCallContext<'e, 'n, 's, 'a, 'm> { - engine: &'e Engine, - fn_name: &'n str, - source: Option<&'s str>, - pub(crate) mods: Option<&'a Imports>, - pub(crate) lib: &'m [&'m Module], +pub struct NativeCallContext<'a> { + engine: &'a Engine, + fn_name: &'a str, + source: Option<&'a str>, + mods: Option<&'a Imports>, + lib: &'a [&'a Module], } -impl<'e, 'n, 's, 'a, 'm, M: AsRef<[&'m Module]> + ?Sized> - From<(&'e Engine, &'n str, Option<&'s str>, &'a Imports, &'m M)> - for NativeCallContext<'e, 'n, 's, 'a, 'm> +impl<'a, M: AsRef<[&'a Module]> + ?Sized> + From<(&'a Engine, &'a str, Option<&'a str>, &'a Imports, &'a M)> for NativeCallContext<'a> { #[inline(always)] - fn from(value: (&'e Engine, &'n str, Option<&'s str>, &'a Imports, &'m M)) -> Self { + fn from(value: (&'a Engine, &'a str, Option<&'a str>, &'a Imports, &'a M)) -> Self { Self { engine: value.0, fn_name: value.1, @@ -79,11 +78,11 @@ impl<'e, 'n, 's, 'a, 'm, M: AsRef<[&'m Module]> + ?Sized> } } -impl<'e, 'n, 'm, M: AsRef<[&'m Module]> + ?Sized> From<(&'e Engine, &'n str, &'m M)> - for NativeCallContext<'e, 'n, '_, '_, 'm> +impl<'a, M: AsRef<[&'a Module]> + ?Sized> From<(&'a Engine, &'a str, &'a M)> + for NativeCallContext<'a> { #[inline(always)] - fn from(value: (&'e Engine, &'n str, &'m M)) -> Self { + fn from(value: (&'a Engine, &'a str, &'a M)) -> Self { Self { engine: value.0, fn_name: value.1, @@ -94,10 +93,10 @@ impl<'e, 'n, 'm, M: AsRef<[&'m Module]> + ?Sized> From<(&'e Engine, &'n str, &'m } } -impl<'e, 'n, 's, 'a, 'm> NativeCallContext<'e, 'n, 's, 'a, 'm> { +impl<'a> NativeCallContext<'a> { /// Create a new [`NativeCallContext`]. #[inline(always)] - pub fn new(engine: &'e Engine, fn_name: &'n str, lib: &'m [&'m Module]) -> Self { + pub fn new(engine: &'a Engine, fn_name: &'a str, lib: &'a [&Module]) -> Self { Self { engine, fn_name, @@ -112,11 +111,11 @@ impl<'e, 'n, 's, 'a, 'm> NativeCallContext<'e, 'n, 's, 'a, 'm> { #[cfg(not(feature = "no_module"))] #[inline(always)] pub fn new_with_all_fields( - engine: &'e Engine, - fn_name: &'n str, - source: &'s Option<&str>, - imports: &'a mut Imports, - lib: &'m [&'m Module], + engine: &'a Engine, + fn_name: &'a str, + source: &'a Option<&str>, + imports: &'a Imports, + lib: &'a [&Module], ) -> Self { Self { engine, @@ -147,6 +146,14 @@ impl<'e, 'n, 's, 'a, 'm> NativeCallContext<'e, 'n, 's, 'a, 'm> { pub fn iter_imports(&self) -> impl Iterator { self.mods.iter().flat_map(|&m| m.iter()) } + /// Get an iterator over the current set of modules imported via `import` statements. + #[cfg(not(feature = "no_module"))] + #[inline(always)] + pub(crate) fn iter_imports_raw( + &self, + ) -> impl Iterator)> { + self.mods.iter().flat_map(|&m| m.iter_raw()) + } /// _(INTERNALS)_ The current set of modules imported via `import` statements. /// Available under the `internals` feature only. #[cfg(feature = "internals")] diff --git a/src/packages/fn_basic.rs b/src/packages/fn_basic.rs index 0f6d851b..e9bd49ff 100644 --- a/src/packages/fn_basic.rs +++ b/src/packages/fn_basic.rs @@ -110,15 +110,13 @@ fn collect_fn_metadata(ctx: NativeCallContext) -> Array { let mut list: Array = Default::default(); - ctx.lib - .iter() + ctx.iter_namespaces() .flat_map(|m| m.iter_script_fn()) .for_each(|(_, _, _, _, f)| list.push(make_metadata(&dict, None, f).into())); - if let Some(mods) = ctx.mods { - mods.iter_raw() - .for_each(|(ns, m)| scan_module(&mut list, &dict, ns.clone(), m.as_ref())); - } + #[cfg(not(feature = "no_module"))] + ctx.iter_imports_raw() + .for_each(|(ns, m)| scan_module(&mut list, &dict, ns.clone(), m.as_ref())); list } diff --git a/src/syntax.rs b/src/syntax.rs index e126af0a..2e39554b 100644 --- a/src/syntax.rs +++ b/src/syntax.rs @@ -58,7 +58,7 @@ impl Expression<'_> { } } -impl EvalContext<'_, '_, '_, '_, '_, '_, '_, '_> { +impl EvalContext<'_, '_, '_, '_, '_, '_, '_> { /// Evaluate an [expression tree][Expression]. /// /// # WARNING - Low Level API diff --git a/src/token.rs b/src/token.rs index d150754b..31c87f30 100644 --- a/src/token.rs +++ b/src/token.rs @@ -30,7 +30,7 @@ type LERR = LexError; const NUM_SEP: char = '_'; /// A stream of tokens. -pub type TokenStream<'a, 't> = Peekable>; +pub type TokenStream<'a> = Peekable>; /// A location (line number + character position) in the input script. /// @@ -1741,9 +1741,9 @@ impl InputStream for MultiInputsStream<'_> { } /// An iterator on a [`Token`] stream. -pub struct TokenIterator<'a, 'e> { +pub struct TokenIterator<'a> { /// Reference to the scripting `Engine`. - engine: &'e Engine, + engine: &'a Engine, /// Current state. state: TokenizeState, /// Current position. @@ -1754,7 +1754,7 @@ pub struct TokenIterator<'a, 'e> { map: Option Token>, } -impl<'a> Iterator for TokenIterator<'a, '_> { +impl<'a> Iterator for TokenIterator<'a> { type Item = (Token, Position); fn next(&mut self) -> Option { @@ -1837,30 +1837,31 @@ impl<'a> Iterator for TokenIterator<'a, '_> { } impl Engine { - /// Tokenize an input text stream. + /// _(INTERNALS)_ Tokenize an input text stream. + /// Exported under the `internals` feature only. + #[cfg(feature = "internals")] #[inline(always)] - pub fn lex<'a, 'e>( - &'e self, - input: impl IntoIterator, - ) -> TokenIterator<'a, 'e> { + pub fn lex<'a>(&'a self, input: impl IntoIterator) -> TokenIterator<'a> { self.lex_raw(input, None) } - /// Tokenize an input text stream with a mapping function. + /// _(INTERNALS)_ Tokenize an input text stream with a mapping function. + /// Exported under the `internals` feature only. + #[cfg(feature = "internals")] #[inline(always)] - pub fn lex_with_map<'a, 'e>( - &'e self, + pub fn lex_with_map<'a>( + &'a self, input: impl IntoIterator, map: fn(Token) -> Token, - ) -> TokenIterator<'a, 'e> { + ) -> TokenIterator<'a> { self.lex_raw(input, Some(map)) } /// Tokenize an input text stream with an optional mapping function. #[inline] - fn lex_raw<'a, 'e>( - &'e self, + pub(crate) fn lex_raw<'a>( + &'a self, input: impl IntoIterator, map: Option Token>, - ) -> TokenIterator<'a, 'e> { + ) -> TokenIterator<'a> { TokenIterator { engine: self, state: TokenizeState {