Simplify lifetimes.

This commit is contained in:
Stephen Chung 2021-03-03 22:49:57 +08:00
parent ed568a9395
commit ade290da7e
9 changed files with 81 additions and 92 deletions

View File

@ -21,6 +21,7 @@ Breaking changes
* `Module::update_fn_metadata` input parameter is changed. * `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`. * 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. * `is_def_var` and `is_def_fn` are now reserved keywords.
* `Engine::id` field is removed.
Enhancements Enhancements
------------ ------------

View File

@ -525,18 +525,6 @@ impl State {
pub fn is_global(&self) -> bool { pub fn is_global(&self) -> bool {
self.scope_level == 0 self.scope_level == 0
} }
/// Get the current functions resolution cache.
pub fn fn_resolution_cache(
&self,
) -> Option<
&HashMap<
NonZeroU64,
Option<(CallableFunction, Option<ImmutableString>)>,
StraightHasherBuilder,
>,
> {
self.fn_resolution_caches.last()
}
/// Get a mutable reference to the current functions resolution cache. /// Get a mutable reference to the current functions resolution cache.
pub fn fn_resolution_cache_mut( pub fn fn_resolution_cache_mut(
&mut self, &mut self,
@ -617,17 +605,17 @@ pub struct Limits {
/// Context of a script evaluation process. /// Context of a script evaluation process.
#[derive(Debug)] #[derive(Debug)]
pub struct EvalContext<'e, 'x, 'px, 'a, 's, 'm, 't, 'pt> { pub struct EvalContext<'a, 'x, 'px, 'm, 's, 't, 'pt> {
pub(crate) engine: &'e Engine, pub(crate) engine: &'a Engine,
pub(crate) scope: &'x mut Scope<'px>, 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) 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) this_ptr: &'t mut Option<&'pt mut Dynamic>,
pub(crate) level: usize, 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`]. /// The current [`Engine`].
#[inline(always)] #[inline(always)]
pub fn engine(&self) -> &Engine { 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 { pub struct Engine {
/// A unique ID identifying this scripting [`Engine`].
pub id: String,
/// A module containing all functions directly loaded into the Engine. /// A module containing all functions directly loaded into the Engine.
pub(crate) global_namespace: Module, pub(crate) global_namespace: Module,
/// A collection of all modules loaded into the global namespace of the Engine. /// 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 { impl fmt::Debug for Engine {
#[inline(always)] #[inline(always)]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if !self.id.is_empty() { f.write_str("Engine")
write!(f, "Engine({})", self.id)
} else {
f.write_str("Engine")
}
} }
} }
@ -819,8 +800,6 @@ impl Engine {
pub fn new() -> Self { pub fn new() -> Self {
// Create the new scripting Engine // Create the new scripting Engine
let mut engine = Self { let mut engine = Self {
id: Default::default(),
global_namespace: Default::default(), global_namespace: Default::default(),
global_modules: Default::default(), global_modules: Default::default(),
global_sub_modules: Default::default(), global_sub_modules: Default::default(),
@ -886,8 +865,6 @@ impl Engine {
#[inline] #[inline]
pub fn new_raw() -> Self { pub fn new_raw() -> Self {
Self { Self {
id: Default::default(),
global_namespace: Default::default(), global_namespace: Default::default(),
global_modules: Default::default(), global_modules: Default::default(),
global_sub_modules: Default::default(), global_sub_modules: Default::default(),
@ -934,14 +911,13 @@ impl Engine {
} }
/// Search for a module within an imports stack. /// Search for a module within an imports stack.
/// [`Position`] in [`EvalAltResult`] is [`NONE`][Position::NONE] and must be set afterwards. pub(crate) fn search_imports(
pub fn search_imports(
&self, &self,
mods: &Imports, mods: &Imports,
state: &mut State, state: &mut State,
namespace: &NamespaceRef, namespace: &NamespaceRef,
) -> Result<Shared<Module>, Box<EvalAltResult>> { ) -> Option<Shared<Module>> {
let Ident { name: root, pos } = &namespace[0]; let root = &namespace[0].name;
// Qualified - check if the root module is directly indexed // Qualified - check if the root module is directly indexed
let index = if state.always_search { let index = if state.always_search {
@ -950,15 +926,14 @@ impl Engine {
namespace.index() namespace.index()
}; };
Ok(if let Some(index) = index { if let Some(index) = index {
let offset = mods.len() - index.get(); let offset = mods.len() - index.get();
mods.get(offset).expect("invalid index in Imports") Some(mods.get(offset).expect("invalid index in Imports"))
} else { } else {
mods.find(root) mods.find(root)
.map(|n| mods.get(n).expect("invalid index in Imports")) .map(|n| mods.get(n).expect("invalid index in Imports"))
.or_else(|| self.global_sub_modules.get(root).cloned()) .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, /// Search for a variable within the scope or within imports,
@ -976,7 +951,12 @@ impl Engine {
Expr::Variable(v) => match v.as_ref() { Expr::Variable(v) => match v.as_ref() {
// Qualified variable // Qualified variable
(_, Some((hash_var, modules)), Ident { name, pos }) => { (_, 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| { let target = module.get_qualified_var(*hash_var).map_err(|mut err| {
match *err { match *err {
EvalAltResult::ErrorVariableNotFound(ref mut err_name, _) => { EvalAltResult::ErrorVariableNotFound(ref mut err_name, _) => {
@ -1068,7 +1048,7 @@ impl Engine {
} }
/// Chain-evaluate a dot/index chain. /// 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")))] #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
fn eval_dot_index_chain_helper( fn eval_dot_index_chain_helper(
&self, &self,

View File

@ -1028,7 +1028,7 @@ impl Engine {
scripts: &[&str], scripts: &[&str],
optimization_level: OptimizationLevel, optimization_level: OptimizationLevel,
) -> Result<AST, ParseError> { ) -> Result<AST, ParseError> {
let stream = self.lex(scripts); let stream = self.lex_raw(scripts, None);
self.parse(&mut stream.peekable(), scope, optimization_level) self.parse(&mut stream.peekable(), scope, optimization_level)
} }
/// Read the contents of a file into a string. /// Read the contents of a file into a string.
@ -1190,9 +1190,9 @@ impl Engine {
.into()); .into());
}; };
let stream = self.lex_with_map( let stream = self.lex_raw(
&scripts, &scripts,
if has_null { Some(if has_null {
|token| match token { |token| match token {
// If `null` is present, make sure `null` is treated as a variable // If `null` is present, make sure `null` is treated as a variable
Token::Reserved(s) if s == "null" => Token::Identifier(s), Token::Reserved(s) if s == "null" => Token::Identifier(s),
@ -1200,7 +1200,7 @@ impl Engine {
} }
} else { } else {
|t| t |t| t
}, }),
); );
let ast = let ast =
@ -1283,7 +1283,7 @@ impl Engine {
script: &str, script: &str,
) -> Result<AST, ParseError> { ) -> Result<AST, ParseError> {
let scripts = [script]; let scripts = [script];
let stream = self.lex(&scripts); let stream = self.lex_raw(&scripts, None);
let mut peekable = stream.peekable(); let mut peekable = stream.peekable();
self.parse_global_expr(&mut peekable, scope, self.optimization_level) self.parse_global_expr(&mut peekable, scope, self.optimization_level)
@ -1444,7 +1444,7 @@ impl Engine {
script: &str, script: &str,
) -> Result<T, Box<EvalAltResult>> { ) -> Result<T, Box<EvalAltResult>> {
let scripts = [script]; let scripts = [script];
let stream = self.lex(&scripts); let stream = self.lex_raw(&scripts, None);
// No need to optimize a lone expression // No need to optimize a lone expression
let ast = self.parse_global_expr(&mut stream.peekable(), scope, OptimizationLevel::None)?; let ast = self.parse_global_expr(&mut stream.peekable(), scope, OptimizationLevel::None)?;
@ -1585,7 +1585,7 @@ impl Engine {
script: &str, script: &str,
) -> Result<(), Box<EvalAltResult>> { ) -> Result<(), Box<EvalAltResult>> {
let scripts = [script]; 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)?; let ast = self.parse(&mut stream.peekable(), scope, self.optimization_level)?;
self.consume_ast_with_scope(scope, &ast) self.consume_ast_with_scope(scope, &ast)
} }

View File

@ -203,7 +203,7 @@ impl Engine {
/// # Examples /// # Examples
/// ///
/// The following will raise an error during parsing because the `if` keyword is disabled /// 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 /// ```rust,should_panic
/// # fn main() -> Result<(), rhai::ParseError> { /// # fn main() -> Result<(), rhai::ParseError> {
@ -214,7 +214,7 @@ impl Engine {
/// engine.disable_symbol("if"); // disable the 'if' keyword /// engine.disable_symbol("if"); // disable the 'if' keyword
/// ///
/// engine.compile("let x = if true { 42 } else { 0 };")?; /// engine.compile("let x = if true { 42 } else { 0 };")?;
/// // ^ 'if' is rejected as a reserved keyword /// // ^ 'if' is rejected as a reserved symbol
/// # Ok(()) /// # Ok(())
/// # } /// # }
/// ``` /// ```

View File

@ -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) // First search in script-defined functions (can override built-in)
let func = match module.get_qualified_fn(hash_script) { let func = match module.get_qualified_fn(hash_script) {

View File

@ -55,20 +55,19 @@ pub type Locked<T> = crate::stdlib::sync::RwLock<T>;
/// Context of a native Rust function call. /// Context of a native Rust function call.
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct NativeCallContext<'e, 'n, 's, 'a, 'm> { pub struct NativeCallContext<'a> {
engine: &'e Engine, engine: &'a Engine,
fn_name: &'n str, fn_name: &'a str,
source: Option<&'s str>, source: Option<&'a str>,
pub(crate) mods: Option<&'a Imports>, mods: Option<&'a Imports>,
pub(crate) lib: &'m [&'m Module], lib: &'a [&'a Module],
} }
impl<'e, 'n, 's, 'a, 'm, M: AsRef<[&'m Module]> + ?Sized> impl<'a, M: AsRef<[&'a Module]> + ?Sized>
From<(&'e Engine, &'n str, Option<&'s str>, &'a Imports, &'m M)> From<(&'a Engine, &'a str, Option<&'a str>, &'a Imports, &'a M)> for NativeCallContext<'a>
for NativeCallContext<'e, 'n, 's, 'a, 'm>
{ {
#[inline(always)] #[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 { Self {
engine: value.0, engine: value.0,
fn_name: value.1, 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)> impl<'a, M: AsRef<[&'a Module]> + ?Sized> From<(&'a Engine, &'a str, &'a M)>
for NativeCallContext<'e, 'n, '_, '_, 'm> for NativeCallContext<'a>
{ {
#[inline(always)] #[inline(always)]
fn from(value: (&'e Engine, &'n str, &'m M)) -> Self { fn from(value: (&'a Engine, &'a str, &'a M)) -> Self {
Self { Self {
engine: value.0, engine: value.0,
fn_name: value.1, 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`]. /// Create a new [`NativeCallContext`].
#[inline(always)] #[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 { Self {
engine, engine,
fn_name, fn_name,
@ -112,11 +111,11 @@ impl<'e, 'n, 's, 'a, 'm> NativeCallContext<'e, 'n, 's, 'a, 'm> {
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
#[inline(always)] #[inline(always)]
pub fn new_with_all_fields( pub fn new_with_all_fields(
engine: &'e Engine, engine: &'a Engine,
fn_name: &'n str, fn_name: &'a str,
source: &'s Option<&str>, source: &'a Option<&str>,
imports: &'a mut Imports, imports: &'a Imports,
lib: &'m [&'m Module], lib: &'a [&Module],
) -> Self { ) -> Self {
Self { Self {
engine, engine,
@ -147,6 +146,14 @@ impl<'e, 'n, 's, 'a, 'm> NativeCallContext<'e, 'n, 's, 'a, 'm> {
pub fn iter_imports(&self) -> impl Iterator<Item = (&str, &Module)> { pub fn iter_imports(&self) -> impl Iterator<Item = (&str, &Module)> {
self.mods.iter().flat_map(|&m| m.iter()) 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<Item = (&ImmutableString, &Shared<Module>)> {
self.mods.iter().flat_map(|&m| m.iter_raw())
}
/// _(INTERNALS)_ The current set of modules imported via `import` statements. /// _(INTERNALS)_ The current set of modules imported via `import` statements.
/// Available under the `internals` feature only. /// Available under the `internals` feature only.
#[cfg(feature = "internals")] #[cfg(feature = "internals")]

View File

@ -110,15 +110,13 @@ fn collect_fn_metadata(ctx: NativeCallContext) -> Array {
let mut list: Array = Default::default(); let mut list: Array = Default::default();
ctx.lib ctx.iter_namespaces()
.iter()
.flat_map(|m| m.iter_script_fn()) .flat_map(|m| m.iter_script_fn())
.for_each(|(_, _, _, _, f)| list.push(make_metadata(&dict, None, f).into())); .for_each(|(_, _, _, _, f)| list.push(make_metadata(&dict, None, f).into()));
if let Some(mods) = ctx.mods { #[cfg(not(feature = "no_module"))]
mods.iter_raw() ctx.iter_imports_raw()
.for_each(|(ns, m)| scan_module(&mut list, &dict, ns.clone(), m.as_ref())); .for_each(|(ns, m)| scan_module(&mut list, &dict, ns.clone(), m.as_ref()));
}
list list
} }

View File

@ -58,7 +58,7 @@ impl Expression<'_> {
} }
} }
impl EvalContext<'_, '_, '_, '_, '_, '_, '_, '_> { impl EvalContext<'_, '_, '_, '_, '_, '_, '_> {
/// Evaluate an [expression tree][Expression]. /// Evaluate an [expression tree][Expression].
/// ///
/// # WARNING - Low Level API /// # WARNING - Low Level API

View File

@ -30,7 +30,7 @@ type LERR = LexError;
const NUM_SEP: char = '_'; const NUM_SEP: char = '_';
/// A stream of tokens. /// A stream of tokens.
pub type TokenStream<'a, 't> = Peekable<TokenIterator<'a, 't>>; pub type TokenStream<'a> = Peekable<TokenIterator<'a>>;
/// A location (line number + character position) in the input script. /// A location (line number + character position) in the input script.
/// ///
@ -1741,9 +1741,9 @@ impl InputStream for MultiInputsStream<'_> {
} }
/// An iterator on a [`Token`] stream. /// An iterator on a [`Token`] stream.
pub struct TokenIterator<'a, 'e> { pub struct TokenIterator<'a> {
/// Reference to the scripting `Engine`. /// Reference to the scripting `Engine`.
engine: &'e Engine, engine: &'a Engine,
/// Current state. /// Current state.
state: TokenizeState, state: TokenizeState,
/// Current position. /// Current position.
@ -1754,7 +1754,7 @@ pub struct TokenIterator<'a, 'e> {
map: Option<fn(Token) -> Token>, map: Option<fn(Token) -> Token>,
} }
impl<'a> Iterator for TokenIterator<'a, '_> { impl<'a> Iterator for TokenIterator<'a> {
type Item = (Token, Position); type Item = (Token, Position);
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
@ -1837,30 +1837,31 @@ impl<'a> Iterator for TokenIterator<'a, '_> {
} }
impl Engine { impl Engine {
/// Tokenize an input text stream. /// _(INTERNALS)_ Tokenize an input text stream.
/// Exported under the `internals` feature only.
#[cfg(feature = "internals")]
#[inline(always)] #[inline(always)]
pub fn lex<'a, 'e>( pub fn lex<'a>(&'a self, input: impl IntoIterator<Item = &'a &'a str>) -> TokenIterator<'a> {
&'e self,
input: impl IntoIterator<Item = &'a &'a str>,
) -> TokenIterator<'a, 'e> {
self.lex_raw(input, None) 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)] #[inline(always)]
pub fn lex_with_map<'a, 'e>( pub fn lex_with_map<'a>(
&'e self, &'a self,
input: impl IntoIterator<Item = &'a &'a str>, input: impl IntoIterator<Item = &'a &'a str>,
map: fn(Token) -> Token, map: fn(Token) -> Token,
) -> TokenIterator<'a, 'e> { ) -> TokenIterator<'a> {
self.lex_raw(input, Some(map)) self.lex_raw(input, Some(map))
} }
/// Tokenize an input text stream with an optional mapping function. /// Tokenize an input text stream with an optional mapping function.
#[inline] #[inline]
fn lex_raw<'a, 'e>( pub(crate) fn lex_raw<'a>(
&'e self, &'a self,
input: impl IntoIterator<Item = &'a &'a str>, input: impl IntoIterator<Item = &'a &'a str>,
map: Option<fn(Token) -> Token>, map: Option<fn(Token) -> Token>,
) -> TokenIterator<'a, 'e> { ) -> TokenIterator<'a> {
TokenIterator { TokenIterator {
engine: self, engine: self,
state: TokenizeState { state: TokenizeState {