Code structure cleanup.
This commit is contained in:
parent
53adc58f63
commit
f5ffbfbe06
427
src/ast.rs
Normal file
427
src/ast.rs
Normal file
@ -0,0 +1,427 @@
|
|||||||
|
//! Module defining the AST (abstract syntax tree).
|
||||||
|
|
||||||
|
use crate::fn_native::Shared;
|
||||||
|
use crate::module::Module;
|
||||||
|
use crate::parser::{FnAccess, ScriptFnDef, Stmt};
|
||||||
|
|
||||||
|
use crate::stdlib::{
|
||||||
|
ops::{Add, AddAssign},
|
||||||
|
vec,
|
||||||
|
vec::Vec,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Compiled AST (abstract syntax tree) of a Rhai script.
|
||||||
|
///
|
||||||
|
/// # Thread Safety
|
||||||
|
///
|
||||||
|
/// Currently, `AST` is neither `Send` nor `Sync`. Turn on the `sync` feature to make it `Send + Sync`.
|
||||||
|
#[derive(Debug, Clone, Default)]
|
||||||
|
pub struct AST(
|
||||||
|
/// Global statements.
|
||||||
|
Vec<Stmt>,
|
||||||
|
/// Script-defined functions.
|
||||||
|
Module,
|
||||||
|
);
|
||||||
|
|
||||||
|
impl AST {
|
||||||
|
/// Create a new `AST`.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn new(statements: Vec<Stmt>, lib: Module) -> Self {
|
||||||
|
Self(statements, lib)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the statements.
|
||||||
|
#[cfg(not(feature = "internals"))]
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn statements(&self) -> &[Stmt] {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// _[INTERNALS]_ Get the statements.
|
||||||
|
/// Exported under the `internals` feature only.
|
||||||
|
#[cfg(feature = "internals")]
|
||||||
|
#[deprecated(note = "this method is volatile and may change")]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn statements(&self) -> &[Stmt] {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a mutable reference to the statements.
|
||||||
|
#[cfg(not(feature = "no_optimize"))]
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn statements_mut(&mut self) -> &mut Vec<Stmt> {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the internal `Module` containing all script-defined functions.
|
||||||
|
#[cfg(not(feature = "internals"))]
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn lib(&self) -> &Module {
|
||||||
|
&self.1
|
||||||
|
}
|
||||||
|
|
||||||
|
/// _[INTERNALS]_ Get the internal `Module` containing all script-defined functions.
|
||||||
|
/// Exported under the `internals` feature only.
|
||||||
|
#[cfg(feature = "internals")]
|
||||||
|
#[deprecated(note = "this method is volatile and may change")]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn lib(&self) -> &Module {
|
||||||
|
&self.1
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clone the `AST`'s functions into a new `AST`.
|
||||||
|
/// No statements are cloned.
|
||||||
|
///
|
||||||
|
/// This operation is cheap because functions are shared.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn clone_functions_only(&self) -> Self {
|
||||||
|
self.clone_functions_only_filtered(|_, _, _| true)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clone the `AST`'s functions into a new `AST` based on a filter predicate.
|
||||||
|
/// No statements are cloned.
|
||||||
|
///
|
||||||
|
/// This operation is cheap because functions are shared.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn clone_functions_only_filtered(
|
||||||
|
&self,
|
||||||
|
mut filter: impl FnMut(FnAccess, &str, usize) -> bool,
|
||||||
|
) -> Self {
|
||||||
|
let mut functions: Module = Default::default();
|
||||||
|
functions.merge_filtered(&self.1, &mut filter);
|
||||||
|
Self(Default::default(), functions)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clone the `AST`'s script statements into a new `AST`.
|
||||||
|
/// No functions are cloned.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn clone_statements_only(&self) -> Self {
|
||||||
|
Self(self.0.clone(), Default::default())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Merge two `AST` into one. Both `AST`'s are untouched and a new, merged, version
|
||||||
|
/// is returned.
|
||||||
|
///
|
||||||
|
/// Statements in the second `AST` are simply appended to the end of the first _without any processing_.
|
||||||
|
/// Thus, the return value of the first `AST` (if using expression-statement syntax) is buried.
|
||||||
|
/// Of course, if the first `AST` uses a `return` statement at the end, then
|
||||||
|
/// the second `AST` will essentially be dead code.
|
||||||
|
///
|
||||||
|
/// All script-defined functions in the second `AST` overwrite similarly-named functions
|
||||||
|
/// in the first `AST` with the same number of parameters.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
||||||
|
/// # #[cfg(not(feature = "no_function"))]
|
||||||
|
/// # {
|
||||||
|
/// use rhai::Engine;
|
||||||
|
///
|
||||||
|
/// let engine = Engine::new();
|
||||||
|
///
|
||||||
|
/// let ast1 = engine.compile(r#"
|
||||||
|
/// fn foo(x) { 42 + x }
|
||||||
|
/// foo(1)
|
||||||
|
/// "#)?;
|
||||||
|
///
|
||||||
|
/// let ast2 = engine.compile(r#"
|
||||||
|
/// fn foo(n) { "hello" + n }
|
||||||
|
/// foo("!")
|
||||||
|
/// "#)?;
|
||||||
|
///
|
||||||
|
/// let ast = ast1.merge(&ast2); // Merge 'ast2' into 'ast1'
|
||||||
|
///
|
||||||
|
/// // Notice that using the '+' operator also works:
|
||||||
|
/// // let ast = &ast1 + &ast2;
|
||||||
|
///
|
||||||
|
/// // 'ast' is essentially:
|
||||||
|
/// //
|
||||||
|
/// // fn foo(n) { "hello" + n } // <- definition of first 'foo' is overwritten
|
||||||
|
/// // foo(1) // <- notice this will be "hello1" instead of 43,
|
||||||
|
/// // // but it is no longer the return value
|
||||||
|
/// // foo("!") // returns "hello!"
|
||||||
|
///
|
||||||
|
/// // Evaluate it
|
||||||
|
/// assert_eq!(engine.eval_ast::<String>(&ast)?, "hello!");
|
||||||
|
/// # }
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn merge(&self, other: &Self) -> Self {
|
||||||
|
self.merge_filtered(other, |_, _, _| true)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Combine one `AST` with another. The second `AST` is consumed.
|
||||||
|
///
|
||||||
|
/// Statements in the second `AST` are simply appended to the end of the first _without any processing_.
|
||||||
|
/// Thus, the return value of the first `AST` (if using expression-statement syntax) is buried.
|
||||||
|
/// Of course, if the first `AST` uses a `return` statement at the end, then
|
||||||
|
/// the second `AST` will essentially be dead code.
|
||||||
|
///
|
||||||
|
/// All script-defined functions in the second `AST` overwrite similarly-named functions
|
||||||
|
/// in the first `AST` with the same number of parameters.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
||||||
|
/// # #[cfg(not(feature = "no_function"))]
|
||||||
|
/// # {
|
||||||
|
/// use rhai::Engine;
|
||||||
|
///
|
||||||
|
/// let engine = Engine::new();
|
||||||
|
///
|
||||||
|
/// let mut ast1 = engine.compile(r#"
|
||||||
|
/// fn foo(x) { 42 + x }
|
||||||
|
/// foo(1)
|
||||||
|
/// "#)?;
|
||||||
|
///
|
||||||
|
/// let ast2 = engine.compile(r#"
|
||||||
|
/// fn foo(n) { "hello" + n }
|
||||||
|
/// foo("!")
|
||||||
|
/// "#)?;
|
||||||
|
///
|
||||||
|
/// ast1.combine(ast2); // Combine 'ast2' into 'ast1'
|
||||||
|
///
|
||||||
|
/// // Notice that using the '+=' operator also works:
|
||||||
|
/// // ast1 += ast2;
|
||||||
|
///
|
||||||
|
/// // 'ast1' is essentially:
|
||||||
|
/// //
|
||||||
|
/// // fn foo(n) { "hello" + n } // <- definition of first 'foo' is overwritten
|
||||||
|
/// // foo(1) // <- notice this will be "hello1" instead of 43,
|
||||||
|
/// // // but it is no longer the return value
|
||||||
|
/// // foo("!") // returns "hello!"
|
||||||
|
///
|
||||||
|
/// // Evaluate it
|
||||||
|
/// assert_eq!(engine.eval_ast::<String>(&ast1)?, "hello!");
|
||||||
|
/// # }
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn combine(&mut self, other: Self) -> &mut Self {
|
||||||
|
self.combine_filtered(other, |_, _, _| true)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Merge two `AST` into one. Both `AST`'s are untouched and a new, merged, version
|
||||||
|
/// is returned.
|
||||||
|
///
|
||||||
|
/// Statements in the second `AST` are simply appended to the end of the first _without any processing_.
|
||||||
|
/// Thus, the return value of the first `AST` (if using expression-statement syntax) is buried.
|
||||||
|
/// Of course, if the first `AST` uses a `return` statement at the end, then
|
||||||
|
/// the second `AST` will essentially be dead code.
|
||||||
|
///
|
||||||
|
/// All script-defined functions in the second `AST` are first selected based on a filter
|
||||||
|
/// predicate, then overwrite similarly-named functions in the first `AST` with the
|
||||||
|
/// same number of parameters.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
||||||
|
/// # #[cfg(not(feature = "no_function"))]
|
||||||
|
/// # {
|
||||||
|
/// use rhai::Engine;
|
||||||
|
///
|
||||||
|
/// let engine = Engine::new();
|
||||||
|
///
|
||||||
|
/// let ast1 = engine.compile(r#"
|
||||||
|
/// fn foo(x) { 42 + x }
|
||||||
|
/// foo(1)
|
||||||
|
/// "#)?;
|
||||||
|
///
|
||||||
|
/// let ast2 = engine.compile(r#"
|
||||||
|
/// fn foo(n) { "hello" + n }
|
||||||
|
/// fn error() { 0 }
|
||||||
|
/// foo("!")
|
||||||
|
/// "#)?;
|
||||||
|
///
|
||||||
|
/// // Merge 'ast2', picking only 'error()' but not 'foo(_)', into 'ast1'
|
||||||
|
/// let ast = ast1.merge_filtered(&ast2, |_, name, params| name == "error" && params == 0);
|
||||||
|
///
|
||||||
|
/// // 'ast' is essentially:
|
||||||
|
/// //
|
||||||
|
/// // fn foo(n) { 42 + n } // <- definition of 'ast1::foo' is not overwritten
|
||||||
|
/// // // because 'ast2::foo' is filtered away
|
||||||
|
/// // foo(1) // <- notice this will be 43 instead of "hello1",
|
||||||
|
/// // // but it is no longer the return value
|
||||||
|
/// // fn error() { 0 } // <- this function passes the filter and is merged
|
||||||
|
/// // foo("!") // <- returns "42!"
|
||||||
|
///
|
||||||
|
/// // Evaluate it
|
||||||
|
/// assert_eq!(engine.eval_ast::<String>(&ast)?, "42!");
|
||||||
|
/// # }
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
pub fn merge_filtered(
|
||||||
|
&self,
|
||||||
|
other: &Self,
|
||||||
|
mut filter: impl FnMut(FnAccess, &str, usize) -> bool,
|
||||||
|
) -> Self {
|
||||||
|
let Self(statements, functions) = self;
|
||||||
|
|
||||||
|
let ast = match (statements.is_empty(), other.0.is_empty()) {
|
||||||
|
(false, false) => {
|
||||||
|
let mut statements = statements.clone();
|
||||||
|
statements.extend(other.0.iter().cloned());
|
||||||
|
statements
|
||||||
|
}
|
||||||
|
(false, true) => statements.clone(),
|
||||||
|
(true, false) => other.0.clone(),
|
||||||
|
(true, true) => vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut functions = functions.clone();
|
||||||
|
functions.merge_filtered(&other.1, &mut filter);
|
||||||
|
|
||||||
|
Self::new(ast, functions)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Combine one `AST` with another. The second `AST` is consumed.
|
||||||
|
///
|
||||||
|
/// Statements in the second `AST` are simply appended to the end of the first _without any processing_.
|
||||||
|
/// Thus, the return value of the first `AST` (if using expression-statement syntax) is buried.
|
||||||
|
/// Of course, if the first `AST` uses a `return` statement at the end, then
|
||||||
|
/// the second `AST` will essentially be dead code.
|
||||||
|
///
|
||||||
|
/// All script-defined functions in the second `AST` are first selected based on a filter
|
||||||
|
/// predicate, then overwrite similarly-named functions in the first `AST` with the
|
||||||
|
/// same number of parameters.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
||||||
|
/// # #[cfg(not(feature = "no_function"))]
|
||||||
|
/// # {
|
||||||
|
/// use rhai::Engine;
|
||||||
|
///
|
||||||
|
/// let engine = Engine::new();
|
||||||
|
///
|
||||||
|
/// let mut ast1 = engine.compile(r#"
|
||||||
|
/// fn foo(x) { 42 + x }
|
||||||
|
/// foo(1)
|
||||||
|
/// "#)?;
|
||||||
|
///
|
||||||
|
/// let ast2 = engine.compile(r#"
|
||||||
|
/// fn foo(n) { "hello" + n }
|
||||||
|
/// fn error() { 0 }
|
||||||
|
/// foo("!")
|
||||||
|
/// "#)?;
|
||||||
|
///
|
||||||
|
/// // Combine 'ast2', picking only 'error()' but not 'foo(_)', into 'ast1'
|
||||||
|
/// ast1.combine_filtered(ast2, |_, name, params| name == "error" && params == 0);
|
||||||
|
///
|
||||||
|
/// // 'ast1' is essentially:
|
||||||
|
/// //
|
||||||
|
/// // fn foo(n) { 42 + n } // <- definition of 'ast1::foo' is not overwritten
|
||||||
|
/// // // because 'ast2::foo' is filtered away
|
||||||
|
/// // foo(1) // <- notice this will be 43 instead of "hello1",
|
||||||
|
/// // // but it is no longer the return value
|
||||||
|
/// // fn error() { 0 } // <- this function passes the filter and is merged
|
||||||
|
/// // foo("!") // <- returns "42!"
|
||||||
|
///
|
||||||
|
/// // Evaluate it
|
||||||
|
/// assert_eq!(engine.eval_ast::<String>(&ast1)?, "42!");
|
||||||
|
/// # }
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn combine_filtered(
|
||||||
|
&mut self,
|
||||||
|
other: Self,
|
||||||
|
mut filter: impl FnMut(FnAccess, &str, usize) -> bool,
|
||||||
|
) -> &mut Self {
|
||||||
|
let Self(ref mut statements, ref mut functions) = self;
|
||||||
|
statements.extend(other.0.into_iter());
|
||||||
|
functions.merge_filtered(&other.1, &mut filter);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Filter out the functions, retaining only some based on a filter predicate.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
||||||
|
/// # #[cfg(not(feature = "no_function"))]
|
||||||
|
/// # {
|
||||||
|
/// use rhai::Engine;
|
||||||
|
///
|
||||||
|
/// let engine = Engine::new();
|
||||||
|
///
|
||||||
|
/// let mut ast = engine.compile(r#"
|
||||||
|
/// fn foo(n) { n + 1 }
|
||||||
|
/// fn bar() { print("hello"); }
|
||||||
|
/// "#)?;
|
||||||
|
///
|
||||||
|
/// // Remove all functions except 'foo(_)'
|
||||||
|
/// ast.retain_functions(|_, name, params| name == "foo" && params == 1);
|
||||||
|
/// # }
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn retain_functions(&mut self, filter: impl FnMut(FnAccess, &str, usize) -> bool) {
|
||||||
|
self.1.retain_functions(filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Iterate through all functions
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn iter_functions<'a>(
|
||||||
|
&'a self,
|
||||||
|
) -> impl Iterator<Item = (FnAccess, &str, usize, Shared<ScriptFnDef>)> + 'a {
|
||||||
|
self.1.iter_script_fn()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clear all function definitions in the `AST`.
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn clear_functions(&mut self) {
|
||||||
|
self.1 = Default::default();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clear all statements in the `AST`, leaving only function definitions.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn clear_statements(&mut self) {
|
||||||
|
self.0 = vec![];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: AsRef<AST>> Add<A> for &AST {
|
||||||
|
type Output = AST;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn add(self, rhs: A) -> Self::Output {
|
||||||
|
self.merge(rhs.as_ref())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: Into<AST>> AddAssign<A> for AST {
|
||||||
|
#[inline(always)]
|
||||||
|
fn add_assign(&mut self, rhs: A) {
|
||||||
|
self.combine(rhs.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<[Stmt]> for AST {
|
||||||
|
#[inline(always)]
|
||||||
|
fn as_ref(&self) -> &[Stmt] {
|
||||||
|
self.statements()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<Module> for AST {
|
||||||
|
#[inline(always)]
|
||||||
|
fn as_ref(&self) -> &Module {
|
||||||
|
self.lib()
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
//! Main module defining the script evaluation `Engine`.
|
//! Main module defining the script evaluation `Engine`.
|
||||||
|
|
||||||
use crate::any::{map_std_type_name, Dynamic, Union, Variant};
|
use crate::dynamic::{map_std_type_name, Dynamic, Union, Variant};
|
||||||
use crate::fn_call::run_builtin_op_assignment;
|
use crate::fn_call::run_builtin_op_assignment;
|
||||||
use crate::fn_native::{Callback, FnPtr, OnVarCallback};
|
use crate::fn_native::{Callback, FnPtr, OnVarCallback};
|
||||||
use crate::module::{Module, ModuleRef};
|
use crate::module::{Module, ModuleRef};
|
||||||
@ -12,7 +12,7 @@ use crate::result::EvalAltResult;
|
|||||||
use crate::scope::{EntryType as ScopeEntryType, Scope};
|
use crate::scope::{EntryType as ScopeEntryType, Scope};
|
||||||
use crate::syntax::CustomSyntax;
|
use crate::syntax::CustomSyntax;
|
||||||
use crate::token::Position;
|
use crate::token::Position;
|
||||||
use crate::{calc_fn_hash, StaticVec};
|
use crate::{calc_native_fn_hash, StaticVec};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
use crate::parser::INT;
|
use crate::parser::INT;
|
||||||
@ -29,7 +29,7 @@ use crate::utils::ImmutableString;
|
|||||||
|
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
use crate::any::DynamicWriteLock;
|
use crate::dynamic::DynamicWriteLock;
|
||||||
|
|
||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
any::type_name,
|
any::type_name,
|
||||||
@ -462,7 +462,7 @@ impl<'e, 'x, 'px, 'a, 's, 'm, 'pm, 't, 'pt> EvalContext<'e, 'x, 'px, 'a, 's, 'm,
|
|||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn imports(&self) -> &'a Imports {
|
pub fn imports(&self) -> &'a Imports {
|
||||||
self.mods
|
self.mods.as_ref()
|
||||||
}
|
}
|
||||||
/// Get an iterator over the namespaces containing definition of all script-defined functions.
|
/// Get an iterator over the namespaces containing definition of all script-defined functions.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
@ -1447,8 +1447,7 @@ impl Engine {
|
|||||||
let args = &mut [&mut lhs_value.clone(), value];
|
let args = &mut [&mut lhs_value.clone(), value];
|
||||||
|
|
||||||
// Qualifiers (none) + function name + number of arguments + argument `TypeId`'s.
|
// Qualifiers (none) + function name + number of arguments + argument `TypeId`'s.
|
||||||
let hash =
|
let hash = calc_native_fn_hash(empty(), op, args.iter().map(|a| a.type_id()));
|
||||||
calc_fn_hash(empty(), op, args.len(), args.iter().map(|a| a.type_id()));
|
|
||||||
|
|
||||||
if self
|
if self
|
||||||
.call_native_fn(state, lib, op, hash, args, false, false, &def_value)
|
.call_native_fn(state, lib, op, hash, args, false, false, &def_value)
|
||||||
@ -1698,7 +1697,7 @@ impl Engine {
|
|||||||
// Qualifiers (none) + function name + number of arguments + argument `TypeId`'s.
|
// Qualifiers (none) + function name + number of arguments + argument `TypeId`'s.
|
||||||
let arg_types =
|
let arg_types =
|
||||||
once(lhs_ptr.as_mut().type_id()).chain(once(rhs_val.type_id()));
|
once(lhs_ptr.as_mut().type_id()).chain(once(rhs_val.type_id()));
|
||||||
let hash_fn = calc_fn_hash(empty(), op, 2, arg_types);
|
let hash_fn = calc_native_fn_hash(empty(), op, arg_types);
|
||||||
|
|
||||||
match self
|
match self
|
||||||
.global_module
|
.global_module
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
//! Module that defines the extern API of `Engine`.
|
//! Module that defines the extern API of `Engine`.
|
||||||
|
|
||||||
use crate::any::{Dynamic, Variant};
|
use crate::ast::AST;
|
||||||
|
use crate::dynamic::{Dynamic, Variant};
|
||||||
use crate::engine::{Engine, EvalContext, Imports, State};
|
use crate::engine::{Engine, EvalContext, Imports, State};
|
||||||
use crate::error::ParseError;
|
|
||||||
use crate::fn_native::{FnCallArgs, NativeCallContext, SendSync};
|
use crate::fn_native::{FnCallArgs, NativeCallContext, SendSync};
|
||||||
use crate::optimize::OptimizationLevel;
|
use crate::optimize::OptimizationLevel;
|
||||||
use crate::parser::AST;
|
use crate::parse_error::ParseError;
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::scope::Scope;
|
use crate::scope::Scope;
|
||||||
use crate::token::Position;
|
use crate::token::Position;
|
||||||
@ -19,7 +19,7 @@ use crate::{
|
|||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
use crate::{
|
use crate::{
|
||||||
engine::{make_getter, make_setter, Map},
|
engine::{make_getter, make_setter, Map},
|
||||||
error::ParseErrorType,
|
parse_error::ParseErrorType,
|
||||||
token::Token,
|
token::Token,
|
||||||
};
|
};
|
||||||
|
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
use crate::any::{Dynamic, Variant};
|
use crate::dynamic::{Dynamic, Variant};
|
||||||
use crate::StaticVec;
|
use crate::StaticVec;
|
||||||
|
|
||||||
/// Trait that represents arguments to a function call.
|
/// Trait that represents arguments to a function call.
|
||||||
|
@ -1,21 +1,21 @@
|
|||||||
//! Implement function-calling mechanism for `Engine`.
|
//! Implement function-calling mechanism for `Engine`.
|
||||||
|
|
||||||
use crate::any::Dynamic;
|
use crate::dynamic::Dynamic;
|
||||||
use crate::engine::{
|
use crate::engine::{
|
||||||
search_imports, Engine, Imports, State, KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR,
|
search_imports, Engine, Imports, State, KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR,
|
||||||
KEYWORD_FN_PTR_CALL, KEYWORD_FN_PTR_CURRY, KEYWORD_IS_DEF_FN, KEYWORD_IS_DEF_VAR,
|
KEYWORD_FN_PTR_CALL, KEYWORD_FN_PTR_CURRY, KEYWORD_IS_DEF_FN, KEYWORD_IS_DEF_VAR,
|
||||||
KEYWORD_PRINT, KEYWORD_TYPE_OF,
|
KEYWORD_PRINT, KEYWORD_TYPE_OF,
|
||||||
};
|
};
|
||||||
use crate::error::ParseErrorType;
|
|
||||||
use crate::fn_native::{FnCallArgs, FnPtr};
|
use crate::fn_native::{FnCallArgs, FnPtr};
|
||||||
use crate::module::{Module, ModuleRef};
|
use crate::module::{Module, ModuleRef};
|
||||||
use crate::optimize::OptimizationLevel;
|
use crate::optimize::OptimizationLevel;
|
||||||
|
use crate::parse_error::ParseErrorType;
|
||||||
use crate::parser::{Expr, ImmutableString, Stmt, INT};
|
use crate::parser::{Expr, ImmutableString, Stmt, INT};
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::scope::Scope;
|
use crate::scope::Scope;
|
||||||
use crate::stdlib::ops::Deref;
|
use crate::stdlib::ops::Deref;
|
||||||
use crate::token::Position;
|
use crate::token::Position;
|
||||||
use crate::{calc_fn_hash, StaticVec};
|
use crate::{calc_native_fn_hash, calc_script_fn_hash, StaticVec};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -439,15 +439,8 @@ impl Engine {
|
|||||||
pub_only: bool,
|
pub_only: bool,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let arg_types = arg_types.as_ref();
|
let arg_types = arg_types.as_ref();
|
||||||
|
let hash_fn = calc_native_fn_hash(empty(), name, arg_types.iter().cloned());
|
||||||
let arg_len = if arg_types.is_empty() {
|
let hash_script = calc_script_fn_hash(empty(), name, arg_types.len());
|
||||||
usize::MAX
|
|
||||||
} else {
|
|
||||||
arg_types.len()
|
|
||||||
};
|
|
||||||
|
|
||||||
let hash_fn = calc_fn_hash(empty(), name, arg_len, arg_types.iter().cloned());
|
|
||||||
let hash_script = calc_fn_hash(empty(), name, arg_types.len(), empty());
|
|
||||||
|
|
||||||
self.has_override(lib, hash_fn, hash_script, pub_only)
|
self.has_override(lib, hash_fn, hash_script, pub_only)
|
||||||
}
|
}
|
||||||
@ -503,17 +496,7 @@ impl Engine {
|
|||||||
|
|
||||||
// Qualifiers (none) + function name + number of arguments + argument `TypeId`'s.
|
// Qualifiers (none) + function name + number of arguments + argument `TypeId`'s.
|
||||||
let arg_types = args.iter().map(|a| a.type_id());
|
let arg_types = args.iter().map(|a| a.type_id());
|
||||||
let hash_fn = calc_fn_hash(
|
let hash_fn = calc_native_fn_hash(empty(), fn_name, arg_types);
|
||||||
empty(),
|
|
||||||
fn_name,
|
|
||||||
if args.is_empty() {
|
|
||||||
// Distinguish between a script function and a native function with no parameters
|
|
||||||
usize::MAX
|
|
||||||
} else {
|
|
||||||
args.len()
|
|
||||||
},
|
|
||||||
arg_types,
|
|
||||||
);
|
|
||||||
|
|
||||||
match fn_name {
|
match fn_name {
|
||||||
// type_of
|
// type_of
|
||||||
@ -741,7 +724,7 @@ impl Engine {
|
|||||||
let hash = if native {
|
let hash = if native {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
calc_fn_hash(empty(), fn_name, args_len, empty())
|
calc_script_fn_hash(empty(), fn_name, args_len)
|
||||||
};
|
};
|
||||||
// Arguments are passed as-is, adding the curried arguments
|
// Arguments are passed as-is, adding the curried arguments
|
||||||
let mut curry = fn_ptr.curry().iter().cloned().collect::<StaticVec<_>>();
|
let mut curry = fn_ptr.curry().iter().cloned().collect::<StaticVec<_>>();
|
||||||
@ -768,7 +751,7 @@ impl Engine {
|
|||||||
let hash = if native {
|
let hash = if native {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
calc_fn_hash(empty(), fn_name, args_len, empty())
|
calc_script_fn_hash(empty(), fn_name, args_len)
|
||||||
};
|
};
|
||||||
// Replace the first argument with the object pointer, adding the curried arguments
|
// Replace the first argument with the object pointer, adding the curried arguments
|
||||||
let mut curry = fn_ptr.curry().iter().cloned().collect::<StaticVec<_>>();
|
let mut curry = fn_ptr.curry().iter().cloned().collect::<StaticVec<_>>();
|
||||||
@ -831,7 +814,7 @@ impl Engine {
|
|||||||
hash = if native {
|
hash = if native {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
calc_fn_hash(empty(), _fn_name, call_args.len(), empty())
|
calc_script_fn_hash(empty(), _fn_name, call_args.len())
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -882,7 +865,7 @@ impl Engine {
|
|||||||
|
|
||||||
// Handle Fn()
|
// Handle Fn()
|
||||||
if name == KEYWORD_FN_PTR && args_expr.len() == 1 {
|
if name == KEYWORD_FN_PTR && args_expr.len() == 1 {
|
||||||
let hash_fn = calc_fn_hash(empty(), name, 1, once(TypeId::of::<ImmutableString>()));
|
let hash_fn = calc_native_fn_hash(empty(), name, once(TypeId::of::<ImmutableString>()));
|
||||||
|
|
||||||
if !self.has_override(lib, hash_fn, hash_script, pub_only) {
|
if !self.has_override(lib, hash_fn, hash_script, pub_only) {
|
||||||
// Fn - only in function call style
|
// Fn - only in function call style
|
||||||
@ -963,12 +946,12 @@ impl Engine {
|
|||||||
|
|
||||||
// Recalculate hash
|
// Recalculate hash
|
||||||
let args_len = args_expr.len() + curry.len();
|
let args_len = args_expr.len() + curry.len();
|
||||||
hash_script = calc_fn_hash(empty(), name, args_len, empty());
|
hash_script = calc_script_fn_hash(empty(), name, args_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle is_def_var()
|
// Handle is_def_var()
|
||||||
if name == KEYWORD_IS_DEF_VAR && args_expr.len() == 1 {
|
if name == KEYWORD_IS_DEF_VAR && args_expr.len() == 1 {
|
||||||
let hash_fn = calc_fn_hash(empty(), name, 1, once(TypeId::of::<ImmutableString>()));
|
let hash_fn = calc_native_fn_hash(empty(), name, once(TypeId::of::<ImmutableString>()));
|
||||||
|
|
||||||
if !self.has_override(lib, hash_fn, hash_script, pub_only) {
|
if !self.has_override(lib, hash_fn, hash_script, pub_only) {
|
||||||
let var_name =
|
let var_name =
|
||||||
@ -982,10 +965,9 @@ impl Engine {
|
|||||||
|
|
||||||
// Handle is_def_fn()
|
// Handle is_def_fn()
|
||||||
if name == KEYWORD_IS_DEF_FN && args_expr.len() == 2 {
|
if name == KEYWORD_IS_DEF_FN && args_expr.len() == 2 {
|
||||||
let hash_fn = calc_fn_hash(
|
let hash_fn = calc_native_fn_hash(
|
||||||
empty(),
|
empty(),
|
||||||
name,
|
name,
|
||||||
2,
|
|
||||||
[TypeId::of::<ImmutableString>(), TypeId::of::<INT>()]
|
[TypeId::of::<ImmutableString>(), TypeId::of::<INT>()]
|
||||||
.iter()
|
.iter()
|
||||||
.cloned(),
|
.cloned(),
|
||||||
@ -1007,7 +989,7 @@ impl Engine {
|
|||||||
return Ok(if num_params < 0 {
|
return Ok(if num_params < 0 {
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
let hash = calc_fn_hash(empty(), fn_name, num_params as usize, empty());
|
let hash = calc_script_fn_hash(empty(), fn_name, num_params as usize);
|
||||||
lib.iter().any(|&m| m.contains_fn(hash, false))
|
lib.iter().any(|&m| m.contains_fn(hash, false))
|
||||||
}
|
}
|
||||||
.into());
|
.into());
|
||||||
@ -1016,7 +998,7 @@ impl Engine {
|
|||||||
|
|
||||||
// Handle eval()
|
// Handle eval()
|
||||||
if name == KEYWORD_EVAL && args_expr.len() == 1 {
|
if name == KEYWORD_EVAL && args_expr.len() == 1 {
|
||||||
let hash_fn = calc_fn_hash(empty(), name, 1, once(TypeId::of::<ImmutableString>()));
|
let hash_fn = calc_native_fn_hash(empty(), name, once(TypeId::of::<ImmutableString>()));
|
||||||
|
|
||||||
if !self.has_override(lib, hash_fn, hash_script, pub_only) {
|
if !self.has_override(lib, hash_fn, hash_script, pub_only) {
|
||||||
// eval - only in function call style
|
// eval - only in function call style
|
||||||
@ -1185,8 +1167,9 @@ impl Engine {
|
|||||||
// 1) Calculate a hash in a similar manner to script-defined functions,
|
// 1) Calculate a hash in a similar manner to script-defined functions,
|
||||||
// i.e. qualifiers + function name + number of arguments.
|
// i.e. qualifiers + function name + number of arguments.
|
||||||
// 2) Calculate a second hash with no qualifiers, empty function name,
|
// 2) Calculate a second hash with no qualifiers, empty function name,
|
||||||
// zero number of arguments, and the actual list of argument `TypeId`'.s
|
// and the actual list of argument `TypeId`'.s
|
||||||
let hash_fn_args = calc_fn_hash(empty(), "", 0, args.iter().map(|a| a.type_id()));
|
let hash_fn_args =
|
||||||
|
calc_native_fn_hash(empty(), "", args.iter().map(|a| a.type_id()));
|
||||||
// 3) The final hash is the XOR of the two hashes.
|
// 3) The final hash is the XOR of the two hashes.
|
||||||
let hash_qualified_fn = hash_script ^ hash_fn_args;
|
let hash_qualified_fn = hash_script ^ hash_fn_args;
|
||||||
|
|
||||||
|
@ -3,10 +3,10 @@
|
|||||||
#![cfg(not(feature = "no_function"))]
|
#![cfg(not(feature = "no_function"))]
|
||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
use crate::any::Variant;
|
use crate::ast::AST;
|
||||||
|
use crate::dynamic::Variant;
|
||||||
use crate::engine::Engine;
|
use crate::engine::Engine;
|
||||||
use crate::error::ParseError;
|
use crate::parse_error::ParseError;
|
||||||
use crate::parser::AST;
|
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::scope::Scope;
|
use crate::scope::Scope;
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//! Module defining interfaces to native-Rust functions.
|
//! Module defining interfaces to native-Rust functions.
|
||||||
|
|
||||||
use crate::any::Dynamic;
|
use crate::dynamic::Dynamic;
|
||||||
use crate::engine::{Engine, EvalContext};
|
use crate::engine::{Engine, EvalContext};
|
||||||
use crate::module::Module;
|
use crate::module::Module;
|
||||||
use crate::parser::{FnAccess, ScriptFnDef};
|
use crate::parser::{FnAccess, ScriptFnDef};
|
||||||
@ -8,7 +8,7 @@ use crate::plugin::PluginFunction;
|
|||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::token::{is_valid_identifier, Position};
|
use crate::token::{is_valid_identifier, Position};
|
||||||
use crate::utils::ImmutableString;
|
use crate::utils::ImmutableString;
|
||||||
use crate::{calc_fn_hash, StaticVec};
|
use crate::{calc_script_fn_hash, StaticVec};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
use crate::engine::FN_ANONYMOUS;
|
use crate::engine::FN_ANONYMOUS;
|
||||||
@ -176,7 +176,7 @@ impl FnPtr {
|
|||||||
|
|
||||||
let has_this = this_ptr.is_some();
|
let has_this = this_ptr.is_some();
|
||||||
let mut args = args_data.iter_mut().collect::<StaticVec<_>>();
|
let mut args = args_data.iter_mut().collect::<StaticVec<_>>();
|
||||||
let hash_script = calc_fn_hash(empty(), fn_name, args.len(), empty());
|
let hash_script = calc_script_fn_hash(empty(), fn_name, args.len());
|
||||||
|
|
||||||
if let Some(obj) = this_ptr {
|
if let Some(obj) = this_ptr {
|
||||||
args.insert(0, obj);
|
args.insert(0, obj);
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
use crate::any::{Dynamic, DynamicWriteLock, Variant};
|
use crate::dynamic::{Dynamic, DynamicWriteLock, Variant};
|
||||||
use crate::engine::Engine;
|
use crate::engine::Engine;
|
||||||
use crate::fn_native::{CallableFunction, FnAny, FnCallArgs, NativeCallContext, SendSync};
|
use crate::fn_native::{CallableFunction, FnAny, FnCallArgs, NativeCallContext, SendSync};
|
||||||
use crate::parser::FnAccess;
|
use crate::parser::FnAccess;
|
||||||
|
22
src/lib.rs
22
src/lib.rs
@ -57,10 +57,11 @@
|
|||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
mod any;
|
mod ast;
|
||||||
mod api;
|
mod dynamic;
|
||||||
mod engine;
|
mod engine;
|
||||||
mod error;
|
mod engine_api;
|
||||||
|
mod engine_settings;
|
||||||
mod fn_args;
|
mod fn_args;
|
||||||
mod fn_call;
|
mod fn_call;
|
||||||
mod fn_func;
|
mod fn_func;
|
||||||
@ -69,36 +70,37 @@ mod fn_register;
|
|||||||
mod module;
|
mod module;
|
||||||
mod optimize;
|
mod optimize;
|
||||||
pub mod packages;
|
pub mod packages;
|
||||||
|
mod parse_error;
|
||||||
mod parser;
|
mod parser;
|
||||||
pub mod plugin;
|
pub mod plugin;
|
||||||
mod result;
|
mod result;
|
||||||
mod scope;
|
mod scope;
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
mod serde_impl;
|
mod serde_impl;
|
||||||
mod settings;
|
|
||||||
mod stdlib;
|
mod stdlib;
|
||||||
mod syntax;
|
mod syntax;
|
||||||
mod token;
|
mod token;
|
||||||
mod r#unsafe;
|
mod r#unsafe;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
pub use any::Dynamic;
|
pub use ast::AST;
|
||||||
|
pub use dynamic::Dynamic;
|
||||||
pub use engine::{Engine, EvalContext};
|
pub use engine::{Engine, EvalContext};
|
||||||
pub use error::{ParseError, ParseErrorType};
|
|
||||||
pub use fn_native::{FnPtr, NativeCallContext};
|
pub use fn_native::{FnPtr, NativeCallContext};
|
||||||
pub use fn_register::{RegisterFn, RegisterResultFn};
|
pub use fn_register::{RegisterFn, RegisterResultFn};
|
||||||
pub use module::Module;
|
pub use module::Module;
|
||||||
pub use parser::{ImmutableString, AST, INT};
|
pub use parse_error::{ParseError, ParseErrorType};
|
||||||
|
pub use parser::{ImmutableString, INT};
|
||||||
pub use result::EvalAltResult;
|
pub use result::EvalAltResult;
|
||||||
pub use scope::Scope;
|
pub use scope::Scope;
|
||||||
pub use syntax::Expression;
|
pub use syntax::Expression;
|
||||||
pub use token::Position;
|
pub use token::Position;
|
||||||
|
|
||||||
#[cfg(feature = "internals")]
|
#[cfg(feature = "internals")]
|
||||||
pub use utils::calc_fn_hash;
|
pub use utils::{calc_native_fn_hash, calc_script_fn_hash};
|
||||||
|
|
||||||
#[cfg(not(feature = "internals"))]
|
#[cfg(not(feature = "internals"))]
|
||||||
pub(crate) use utils::calc_fn_hash;
|
pub(crate) use utils::{calc_native_fn_hash, calc_script_fn_hash};
|
||||||
|
|
||||||
pub use rhai_codegen::*;
|
pub use rhai_codegen::*;
|
||||||
|
|
||||||
@ -141,7 +143,7 @@ pub use optimize::OptimizationLevel;
|
|||||||
|
|
||||||
#[cfg(feature = "internals")]
|
#[cfg(feature = "internals")]
|
||||||
#[deprecated(note = "this type is volatile and may change")]
|
#[deprecated(note = "this type is volatile and may change")]
|
||||||
pub use error::LexError;
|
pub use parse_error::LexError;
|
||||||
|
|
||||||
#[cfg(feature = "internals")]
|
#[cfg(feature = "internals")]
|
||||||
#[deprecated(note = "this type is volatile and may change")]
|
#[deprecated(note = "this type is volatile and may change")]
|
||||||
|
@ -1,21 +1,21 @@
|
|||||||
//! Module defining external-loaded modules for Rhai.
|
//! Module defining external-loaded modules for Rhai.
|
||||||
|
|
||||||
use crate::any::{Dynamic, Variant};
|
use crate::dynamic::{Dynamic, Variant};
|
||||||
use crate::fn_native::{CallableFunction, FnCallArgs, IteratorFn, NativeCallContext, SendSync};
|
use crate::fn_native::{CallableFunction, FnCallArgs, IteratorFn, NativeCallContext, SendSync};
|
||||||
use crate::fn_register::by_value as cast_arg;
|
use crate::fn_register::by_value as cast_arg;
|
||||||
use crate::parser::FnAccess;
|
use crate::parser::FnAccess;
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::token::{Position, Token};
|
use crate::token::{Position, Token};
|
||||||
use crate::utils::{ImmutableString, StraightHasherBuilder};
|
use crate::utils::{ImmutableString, StraightHasherBuilder};
|
||||||
use crate::{calc_fn_hash, StaticVec};
|
use crate::{calc_native_fn_hash, calc_script_fn_hash, StaticVec};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
use crate::{fn_native::Shared, parser::ScriptFnDef};
|
use crate::{fn_native::Shared, parser::ScriptFnDef};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
use crate::{
|
use crate::{
|
||||||
|
ast::AST,
|
||||||
engine::{Engine, Imports},
|
engine::{Engine, Imports},
|
||||||
parser::AST,
|
|
||||||
scope::{Entry as ScopeEntry, Scope},
|
scope::{Entry as ScopeEntry, Scope},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -268,7 +268,7 @@ impl Module {
|
|||||||
/// Get a mutable reference to a modules-qualified variable.
|
/// Get a mutable reference to a modules-qualified variable.
|
||||||
/// Name and Position in `EvalAltResult` are None and must be set afterwards.
|
/// Name and Position in `EvalAltResult` are None and must be set afterwards.
|
||||||
///
|
///
|
||||||
/// The `u64` hash is calculated by the function `crate::calc_fn_hash`.
|
/// The `u64` hash is calculated by the function `crate::calc_native_fn_hash`.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn get_qualified_var_mut(
|
pub(crate) fn get_qualified_var_mut(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -291,7 +291,7 @@ impl Module {
|
|||||||
pub(crate) fn set_script_fn(&mut self, fn_def: Shared<ScriptFnDef>) -> u64 {
|
pub(crate) fn set_script_fn(&mut self, fn_def: Shared<ScriptFnDef>) -> u64 {
|
||||||
// None + function name + number of arguments.
|
// None + function name + number of arguments.
|
||||||
let num_params = fn_def.params.len();
|
let num_params = fn_def.params.len();
|
||||||
let hash_script = calc_fn_hash(empty(), &fn_def.name, num_params, empty());
|
let hash_script = calc_script_fn_hash(empty(), &fn_def.name, num_params);
|
||||||
self.functions.insert(
|
self.functions.insert(
|
||||||
hash_script,
|
hash_script,
|
||||||
(
|
(
|
||||||
@ -399,7 +399,7 @@ impl Module {
|
|||||||
|
|
||||||
/// Does the particular Rust function exist in the module?
|
/// Does the particular Rust function exist in the module?
|
||||||
///
|
///
|
||||||
/// The `u64` hash is calculated by the function `crate::calc_fn_hash`.
|
/// The `u64` hash is calculated by the function `crate::calc_native_fn_hash`.
|
||||||
/// It is also returned by the `set_fn_XXX` calls.
|
/// It is also returned by the `set_fn_XXX` calls.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
@ -441,31 +441,24 @@ impl Module {
|
|||||||
) -> u64 {
|
) -> u64 {
|
||||||
let name = name.into();
|
let name = name.into();
|
||||||
|
|
||||||
let args_len = if arg_types.is_empty() {
|
let hash_fn = calc_native_fn_hash(empty(), &name, arg_types.iter().cloned());
|
||||||
// Distinguish between a script function and a function with no parameters
|
|
||||||
usize::MAX
|
|
||||||
} else {
|
|
||||||
arg_types.len()
|
|
||||||
};
|
|
||||||
|
|
||||||
let params = arg_types
|
let params = arg_types
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
.map(|id| {
|
.map(|id| {
|
||||||
if id == TypeId::of::<&str>() {
|
if id == TypeId::of::<&str>() || id == TypeId::of::<String>() {
|
||||||
TypeId::of::<ImmutableString>()
|
|
||||||
} else if id == TypeId::of::<String>() {
|
|
||||||
TypeId::of::<ImmutableString>()
|
TypeId::of::<ImmutableString>()
|
||||||
} else {
|
} else {
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect::<StaticVec<_>>();
|
||||||
|
|
||||||
let hash_fn = calc_fn_hash(empty(), &name, args_len, arg_types.iter().cloned());
|
self.functions.insert(
|
||||||
|
hash_fn,
|
||||||
self.functions
|
(name, access, params.len(), Some(params), func.into()),
|
||||||
.insert(hash_fn, (name, access, args_len, Some(params), func.into()));
|
);
|
||||||
|
|
||||||
self.indexed = false;
|
self.indexed = false;
|
||||||
|
|
||||||
@ -1094,7 +1087,7 @@ impl Module {
|
|||||||
|
|
||||||
/// Get a Rust function.
|
/// Get a Rust function.
|
||||||
///
|
///
|
||||||
/// The `u64` hash is calculated by the function `crate::calc_fn_hash`.
|
/// The `u64` hash is calculated by the function `crate::calc_native_fn_hash`.
|
||||||
/// It is also returned by the `set_fn_XXX` calls.
|
/// It is also returned by the `set_fn_XXX` calls.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn get_fn(&self, hash_fn: u64, public_only: bool) -> Option<&CallableFunction> {
|
pub(crate) fn get_fn(&self, hash_fn: u64, public_only: bool) -> Option<&CallableFunction> {
|
||||||
@ -1114,7 +1107,7 @@ impl Module {
|
|||||||
/// Get a modules-qualified function.
|
/// Get a modules-qualified function.
|
||||||
/// Name and Position in `EvalAltResult` are None and must be set afterwards.
|
/// Name and Position in `EvalAltResult` are None and must be set afterwards.
|
||||||
///
|
///
|
||||||
/// The `u64` hash is calculated by the function `crate::calc_fn_hash` and must match
|
/// The `u64` hash is calculated by the function `crate::calc_native_fn_hash` and must match
|
||||||
/// the hash calculated by `index_all_sub_modules`.
|
/// the hash calculated by `index_all_sub_modules`.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn get_qualified_fn(&self, hash_qualified_fn: u64) -> Option<&CallableFunction> {
|
pub(crate) fn get_qualified_fn(&self, hash_qualified_fn: u64) -> Option<&CallableFunction> {
|
||||||
@ -1408,7 +1401,7 @@ impl Module {
|
|||||||
// Index all variables
|
// Index all variables
|
||||||
module.variables.iter().for_each(|(var_name, value)| {
|
module.variables.iter().for_each(|(var_name, value)| {
|
||||||
// Qualifiers + variable name
|
// Qualifiers + variable name
|
||||||
let hash_var = calc_fn_hash(qualifiers.iter().map(|&v| v), var_name, 0, empty());
|
let hash_var = calc_script_fn_hash(qualifiers.iter().map(|&v| v), var_name, 0);
|
||||||
variables.push((hash_var, value.clone()));
|
variables.push((hash_var, value.clone()));
|
||||||
});
|
});
|
||||||
// Index all Rust functions
|
// Index all Rust functions
|
||||||
@ -1422,10 +1415,10 @@ impl Module {
|
|||||||
// 1) Calculate a hash in a similar manner to script-defined functions,
|
// 1) Calculate a hash in a similar manner to script-defined functions,
|
||||||
// i.e. qualifiers + function name + number of arguments.
|
// i.e. qualifiers + function name + number of arguments.
|
||||||
let hash_qualified_script =
|
let hash_qualified_script =
|
||||||
calc_fn_hash(qualifiers.iter().cloned(), name, params.len(), empty());
|
calc_script_fn_hash(qualifiers.iter().cloned(), name, params.len());
|
||||||
// 2) Calculate a second hash with no qualifiers, empty function name,
|
// 2) Calculate a second hash with no qualifiers, empty function name,
|
||||||
// zero number of arguments, and the actual list of argument `TypeId`'.s
|
// and the actual list of argument `TypeId`'.s
|
||||||
let hash_fn_args = calc_fn_hash(empty(), "", 0, params.iter().cloned());
|
let hash_fn_args = calc_native_fn_hash(empty(), "", params.iter().cloned());
|
||||||
// 3) The final hash is the XOR of the two hashes.
|
// 3) The final hash is the XOR of the two hashes.
|
||||||
let hash_qualified_fn = hash_qualified_script ^ hash_fn_args;
|
let hash_qualified_fn = hash_qualified_script ^ hash_fn_args;
|
||||||
|
|
||||||
@ -1435,12 +1428,7 @@ impl Module {
|
|||||||
_hash
|
_hash
|
||||||
} else {
|
} else {
|
||||||
// Qualifiers + function name + number of arguments.
|
// Qualifiers + function name + number of arguments.
|
||||||
calc_fn_hash(
|
calc_script_fn_hash(qualifiers.iter().map(|&v| v), &name, *_num_params)
|
||||||
qualifiers.iter().map(|&v| v),
|
|
||||||
&name,
|
|
||||||
*_num_params,
|
|
||||||
empty(),
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
functions.push((hash_qualified_script, func.clone()));
|
functions.push((hash_qualified_script, func.clone()));
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
|
use crate::ast::AST;
|
||||||
use crate::engine::Engine;
|
use crate::engine::Engine;
|
||||||
use crate::fn_native::Locked;
|
use crate::fn_native::Locked;
|
||||||
use crate::module::{Module, ModuleResolver};
|
use crate::module::{Module, ModuleResolver};
|
||||||
use crate::parser::AST;
|
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::token::Position;
|
use crate::token::Position;
|
||||||
|
|
||||||
|
@ -1,16 +1,17 @@
|
|||||||
//! Module implementing the AST optimizer.
|
//! Module implementing the AST optimizer.
|
||||||
|
|
||||||
use crate::any::Dynamic;
|
use crate::ast::AST;
|
||||||
|
use crate::dynamic::Dynamic;
|
||||||
use crate::engine::{
|
use crate::engine::{
|
||||||
Engine, KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_IS_DEF_FN, KEYWORD_IS_DEF_VAR, KEYWORD_PRINT,
|
Engine, KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_IS_DEF_FN, KEYWORD_IS_DEF_VAR, KEYWORD_PRINT,
|
||||||
KEYWORD_TYPE_OF,
|
KEYWORD_TYPE_OF,
|
||||||
};
|
};
|
||||||
use crate::fn_call::run_builtin_binary_op;
|
use crate::fn_call::run_builtin_binary_op;
|
||||||
use crate::module::Module;
|
use crate::module::Module;
|
||||||
use crate::parser::{map_dynamic_to_expr, BinaryExpr, CustomExpr, Expr, ScriptFnDef, Stmt, AST};
|
use crate::parser::{map_dynamic_to_expr, BinaryExpr, CustomExpr, Expr, ScriptFnDef, Stmt};
|
||||||
use crate::scope::{Entry as ScopeEntry, Scope};
|
use crate::scope::{Entry as ScopeEntry, Scope};
|
||||||
use crate::token::{is_valid_identifier, Position};
|
use crate::token::{is_valid_identifier, Position};
|
||||||
use crate::{calc_fn_hash, StaticVec};
|
use crate::{calc_native_fn_hash, StaticVec};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
use crate::parser::ReturnType;
|
use crate::parser::ReturnType;
|
||||||
@ -134,12 +135,7 @@ fn call_fn_with_constant_arguments(
|
|||||||
arg_values: &mut [Dynamic],
|
arg_values: &mut [Dynamic],
|
||||||
) -> Option<Dynamic> {
|
) -> Option<Dynamic> {
|
||||||
// Search built-in's and external functions
|
// Search built-in's and external functions
|
||||||
let hash_fn = calc_fn_hash(
|
let hash_fn = calc_native_fn_hash(empty(), fn_name, arg_values.iter().map(|a| a.type_id()));
|
||||||
empty(),
|
|
||||||
fn_name,
|
|
||||||
arg_values.len(),
|
|
||||||
arg_values.iter().map(|a| a.type_id()),
|
|
||||||
);
|
|
||||||
|
|
||||||
state
|
state
|
||||||
.engine
|
.engine
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#![cfg(not(feature = "no_index"))]
|
#![cfg(not(feature = "no_index"))]
|
||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
use crate::any::Dynamic;
|
use crate::dynamic::Dynamic;
|
||||||
use crate::def_package;
|
use crate::def_package;
|
||||||
use crate::engine::Array;
|
use crate::engine::Array;
|
||||||
use crate::fn_native::{FnPtr, NativeCallContext};
|
use crate::fn_native::{FnPtr, NativeCallContext};
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::any::Dynamic;
|
use crate::dynamic::Dynamic;
|
||||||
use crate::def_package;
|
use crate::def_package;
|
||||||
use crate::parser::ImmutableString;
|
use crate::parser::ImmutableString;
|
||||||
use crate::plugin::*;
|
use crate::plugin::*;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::any::Variant;
|
use crate::dynamic::Variant;
|
||||||
use crate::def_package;
|
use crate::def_package;
|
||||||
use crate::parser::INT;
|
use crate::parser::INT;
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#![cfg(not(feature = "no_object"))]
|
#![cfg(not(feature = "no_object"))]
|
||||||
|
|
||||||
use crate::any::Dynamic;
|
|
||||||
use crate::def_package;
|
use crate::def_package;
|
||||||
|
use crate::dynamic::Dynamic;
|
||||||
use crate::engine::Map;
|
use crate::engine::Map;
|
||||||
use crate::parser::{ImmutableString, INT};
|
use crate::parser::{ImmutableString, INT};
|
||||||
use crate::plugin::*;
|
use crate::plugin::*;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
use crate::any::Dynamic;
|
|
||||||
use crate::def_package;
|
use crate::def_package;
|
||||||
|
use crate::dynamic::Dynamic;
|
||||||
use crate::fn_native::FnPtr;
|
use crate::fn_native::FnPtr;
|
||||||
use crate::parser::{ImmutableString, INT};
|
use crate::parser::{ImmutableString, INT};
|
||||||
use crate::plugin::*;
|
use crate::plugin::*;
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
use super::{arithmetic::make_err as make_arithmetic_err, math_basic::MAX_INT};
|
use super::{arithmetic::make_err as make_arithmetic_err, math_basic::MAX_INT};
|
||||||
|
|
||||||
use crate::any::Dynamic;
|
|
||||||
use crate::def_package;
|
use crate::def_package;
|
||||||
|
use crate::dynamic::Dynamic;
|
||||||
use crate::parser::INT;
|
use crate::parser::INT;
|
||||||
use crate::plugin::*;
|
use crate::plugin::*;
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
|
453
src/parser.rs
453
src/parser.rs
@ -1,16 +1,17 @@
|
|||||||
//! Main module defining the lexer and parser.
|
//! Main module defining the lexer and parser.
|
||||||
|
|
||||||
use crate::any::{Dynamic, Union};
|
use crate::ast::AST;
|
||||||
|
use crate::dynamic::{Dynamic, Union};
|
||||||
use crate::engine::{Engine, KEYWORD_THIS, MARKER_BLOCK, MARKER_EXPR, MARKER_IDENT};
|
use crate::engine::{Engine, KEYWORD_THIS, MARKER_BLOCK, MARKER_EXPR, MARKER_IDENT};
|
||||||
use crate::error::{LexError, ParseError, ParseErrorType};
|
|
||||||
use crate::fn_native::{FnPtr, Shared};
|
use crate::fn_native::{FnPtr, Shared};
|
||||||
use crate::module::{Module, ModuleRef};
|
use crate::module::{Module, ModuleRef};
|
||||||
use crate::optimize::{optimize_into_ast, OptimizationLevel};
|
use crate::optimize::{optimize_into_ast, OptimizationLevel};
|
||||||
|
use crate::parse_error::{LexError, ParseError, ParseErrorType};
|
||||||
use crate::scope::{EntryType as ScopeEntryType, Scope};
|
use crate::scope::{EntryType as ScopeEntryType, Scope};
|
||||||
use crate::syntax::{CustomSyntax, FnCustomSyntaxEval};
|
use crate::syntax::{CustomSyntax, FnCustomSyntaxEval};
|
||||||
use crate::token::{is_keyword_function, is_valid_identifier, Position, Token, TokenStream};
|
use crate::token::{is_keyword_function, is_valid_identifier, Position, Token, TokenStream};
|
||||||
use crate::utils::StraightHasherBuilder;
|
use crate::utils::StraightHasherBuilder;
|
||||||
use crate::{calc_fn_hash, StaticVec};
|
use crate::{calc_script_fn_hash, StaticVec};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
use crate::engine::Array;
|
use crate::engine::Array;
|
||||||
@ -31,7 +32,6 @@ use crate::stdlib::{
|
|||||||
hash::{Hash, Hasher},
|
hash::{Hash, Hasher},
|
||||||
iter::empty,
|
iter::empty,
|
||||||
num::NonZeroUsize,
|
num::NonZeroUsize,
|
||||||
ops::{Add, AddAssign},
|
|
||||||
string::{String, ToString},
|
string::{String, ToString},
|
||||||
vec,
|
vec,
|
||||||
vec::Vec,
|
vec::Vec,
|
||||||
@ -72,422 +72,6 @@ pub use crate::utils::ImmutableString;
|
|||||||
|
|
||||||
type FunctionsLib = HashMap<u64, ScriptFnDef, StraightHasherBuilder>;
|
type FunctionsLib = HashMap<u64, ScriptFnDef, StraightHasherBuilder>;
|
||||||
|
|
||||||
/// Compiled AST (abstract syntax tree) of a Rhai script.
|
|
||||||
///
|
|
||||||
/// # Thread Safety
|
|
||||||
///
|
|
||||||
/// Currently, `AST` is neither `Send` nor `Sync`. Turn on the `sync` feature to make it `Send + Sync`.
|
|
||||||
#[derive(Debug, Clone, Default)]
|
|
||||||
pub struct AST(
|
|
||||||
/// Global statements.
|
|
||||||
Vec<Stmt>,
|
|
||||||
/// Script-defined functions.
|
|
||||||
Module,
|
|
||||||
);
|
|
||||||
|
|
||||||
impl AST {
|
|
||||||
/// Create a new `AST`.
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn new(statements: Vec<Stmt>, lib: Module) -> Self {
|
|
||||||
Self(statements, lib)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the statements.
|
|
||||||
#[cfg(not(feature = "internals"))]
|
|
||||||
#[inline(always)]
|
|
||||||
pub(crate) fn statements(&self) -> &[Stmt] {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
|
|
||||||
/// _[INTERNALS]_ Get the statements.
|
|
||||||
/// Exported under the `internals` feature only.
|
|
||||||
#[cfg(feature = "internals")]
|
|
||||||
#[deprecated(note = "this method is volatile and may change")]
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn statements(&self) -> &[Stmt] {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get a mutable reference to the statements.
|
|
||||||
#[cfg(not(feature = "no_optimize"))]
|
|
||||||
#[inline(always)]
|
|
||||||
pub(crate) fn statements_mut(&mut self) -> &mut Vec<Stmt> {
|
|
||||||
&mut self.0
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the internal `Module` containing all script-defined functions.
|
|
||||||
#[cfg(not(feature = "internals"))]
|
|
||||||
#[inline(always)]
|
|
||||||
pub(crate) fn lib(&self) -> &Module {
|
|
||||||
&self.1
|
|
||||||
}
|
|
||||||
|
|
||||||
/// _[INTERNALS]_ Get the internal `Module` containing all script-defined functions.
|
|
||||||
/// Exported under the `internals` feature only.
|
|
||||||
#[cfg(feature = "internals")]
|
|
||||||
#[deprecated(note = "this method is volatile and may change")]
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn lib(&self) -> &Module {
|
|
||||||
&self.1
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Clone the `AST`'s functions into a new `AST`.
|
|
||||||
/// No statements are cloned.
|
|
||||||
///
|
|
||||||
/// This operation is cheap because functions are shared.
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn clone_functions_only(&self) -> Self {
|
|
||||||
self.clone_functions_only_filtered(|_, _, _| true)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Clone the `AST`'s functions into a new `AST` based on a filter predicate.
|
|
||||||
/// No statements are cloned.
|
|
||||||
///
|
|
||||||
/// This operation is cheap because functions are shared.
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn clone_functions_only_filtered(
|
|
||||||
&self,
|
|
||||||
mut filter: impl FnMut(FnAccess, &str, usize) -> bool,
|
|
||||||
) -> Self {
|
|
||||||
let mut functions: Module = Default::default();
|
|
||||||
functions.merge_filtered(&self.1, &mut filter);
|
|
||||||
Self(Default::default(), functions)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Clone the `AST`'s script statements into a new `AST`.
|
|
||||||
/// No functions are cloned.
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn clone_statements_only(&self) -> Self {
|
|
||||||
Self(self.0.clone(), Default::default())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Merge two `AST` into one. Both `AST`'s are untouched and a new, merged, version
|
|
||||||
/// is returned.
|
|
||||||
///
|
|
||||||
/// Statements in the second `AST` are simply appended to the end of the first _without any processing_.
|
|
||||||
/// Thus, the return value of the first `AST` (if using expression-statement syntax) is buried.
|
|
||||||
/// Of course, if the first `AST` uses a `return` statement at the end, then
|
|
||||||
/// the second `AST` will essentially be dead code.
|
|
||||||
///
|
|
||||||
/// All script-defined functions in the second `AST` overwrite similarly-named functions
|
|
||||||
/// in the first `AST` with the same number of parameters.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
|
||||||
/// # #[cfg(not(feature = "no_function"))]
|
|
||||||
/// # {
|
|
||||||
/// use rhai::Engine;
|
|
||||||
///
|
|
||||||
/// let engine = Engine::new();
|
|
||||||
///
|
|
||||||
/// let ast1 = engine.compile(r#"
|
|
||||||
/// fn foo(x) { 42 + x }
|
|
||||||
/// foo(1)
|
|
||||||
/// "#)?;
|
|
||||||
///
|
|
||||||
/// let ast2 = engine.compile(r#"
|
|
||||||
/// fn foo(n) { "hello" + n }
|
|
||||||
/// foo("!")
|
|
||||||
/// "#)?;
|
|
||||||
///
|
|
||||||
/// let ast = ast1.merge(&ast2); // Merge 'ast2' into 'ast1'
|
|
||||||
///
|
|
||||||
/// // Notice that using the '+' operator also works:
|
|
||||||
/// // let ast = &ast1 + &ast2;
|
|
||||||
///
|
|
||||||
/// // 'ast' is essentially:
|
|
||||||
/// //
|
|
||||||
/// // fn foo(n) { "hello" + n } // <- definition of first 'foo' is overwritten
|
|
||||||
/// // foo(1) // <- notice this will be "hello1" instead of 43,
|
|
||||||
/// // // but it is no longer the return value
|
|
||||||
/// // foo("!") // returns "hello!"
|
|
||||||
///
|
|
||||||
/// // Evaluate it
|
|
||||||
/// assert_eq!(engine.eval_ast::<String>(&ast)?, "hello!");
|
|
||||||
/// # }
|
|
||||||
/// # Ok(())
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn merge(&self, other: &Self) -> Self {
|
|
||||||
self.merge_filtered(other, |_, _, _| true)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Combine one `AST` with another. The second `AST` is consumed.
|
|
||||||
///
|
|
||||||
/// Statements in the second `AST` are simply appended to the end of the first _without any processing_.
|
|
||||||
/// Thus, the return value of the first `AST` (if using expression-statement syntax) is buried.
|
|
||||||
/// Of course, if the first `AST` uses a `return` statement at the end, then
|
|
||||||
/// the second `AST` will essentially be dead code.
|
|
||||||
///
|
|
||||||
/// All script-defined functions in the second `AST` overwrite similarly-named functions
|
|
||||||
/// in the first `AST` with the same number of parameters.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
|
||||||
/// # #[cfg(not(feature = "no_function"))]
|
|
||||||
/// # {
|
|
||||||
/// use rhai::Engine;
|
|
||||||
///
|
|
||||||
/// let engine = Engine::new();
|
|
||||||
///
|
|
||||||
/// let mut ast1 = engine.compile(r#"
|
|
||||||
/// fn foo(x) { 42 + x }
|
|
||||||
/// foo(1)
|
|
||||||
/// "#)?;
|
|
||||||
///
|
|
||||||
/// let ast2 = engine.compile(r#"
|
|
||||||
/// fn foo(n) { "hello" + n }
|
|
||||||
/// foo("!")
|
|
||||||
/// "#)?;
|
|
||||||
///
|
|
||||||
/// ast1.combine(ast2); // Combine 'ast2' into 'ast1'
|
|
||||||
///
|
|
||||||
/// // Notice that using the '+=' operator also works:
|
|
||||||
/// // ast1 += ast2;
|
|
||||||
///
|
|
||||||
/// // 'ast1' is essentially:
|
|
||||||
/// //
|
|
||||||
/// // fn foo(n) { "hello" + n } // <- definition of first 'foo' is overwritten
|
|
||||||
/// // foo(1) // <- notice this will be "hello1" instead of 43,
|
|
||||||
/// // // but it is no longer the return value
|
|
||||||
/// // foo("!") // returns "hello!"
|
|
||||||
///
|
|
||||||
/// // Evaluate it
|
|
||||||
/// assert_eq!(engine.eval_ast::<String>(&ast1)?, "hello!");
|
|
||||||
/// # }
|
|
||||||
/// # Ok(())
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn combine(&mut self, other: Self) -> &mut Self {
|
|
||||||
self.combine_filtered(other, |_, _, _| true)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Merge two `AST` into one. Both `AST`'s are untouched and a new, merged, version
|
|
||||||
/// is returned.
|
|
||||||
///
|
|
||||||
/// Statements in the second `AST` are simply appended to the end of the first _without any processing_.
|
|
||||||
/// Thus, the return value of the first `AST` (if using expression-statement syntax) is buried.
|
|
||||||
/// Of course, if the first `AST` uses a `return` statement at the end, then
|
|
||||||
/// the second `AST` will essentially be dead code.
|
|
||||||
///
|
|
||||||
/// All script-defined functions in the second `AST` are first selected based on a filter
|
|
||||||
/// predicate, then overwrite similarly-named functions in the first `AST` with the
|
|
||||||
/// same number of parameters.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
|
||||||
/// # #[cfg(not(feature = "no_function"))]
|
|
||||||
/// # {
|
|
||||||
/// use rhai::Engine;
|
|
||||||
///
|
|
||||||
/// let engine = Engine::new();
|
|
||||||
///
|
|
||||||
/// let ast1 = engine.compile(r#"
|
|
||||||
/// fn foo(x) { 42 + x }
|
|
||||||
/// foo(1)
|
|
||||||
/// "#)?;
|
|
||||||
///
|
|
||||||
/// let ast2 = engine.compile(r#"
|
|
||||||
/// fn foo(n) { "hello" + n }
|
|
||||||
/// fn error() { 0 }
|
|
||||||
/// foo("!")
|
|
||||||
/// "#)?;
|
|
||||||
///
|
|
||||||
/// // Merge 'ast2', picking only 'error()' but not 'foo(_)', into 'ast1'
|
|
||||||
/// let ast = ast1.merge_filtered(&ast2, |_, name, params| name == "error" && params == 0);
|
|
||||||
///
|
|
||||||
/// // 'ast' is essentially:
|
|
||||||
/// //
|
|
||||||
/// // fn foo(n) { 42 + n } // <- definition of 'ast1::foo' is not overwritten
|
|
||||||
/// // // because 'ast2::foo' is filtered away
|
|
||||||
/// // foo(1) // <- notice this will be 43 instead of "hello1",
|
|
||||||
/// // // but it is no longer the return value
|
|
||||||
/// // fn error() { 0 } // <- this function passes the filter and is merged
|
|
||||||
/// // foo("!") // <- returns "42!"
|
|
||||||
///
|
|
||||||
/// // Evaluate it
|
|
||||||
/// assert_eq!(engine.eval_ast::<String>(&ast)?, "42!");
|
|
||||||
/// # }
|
|
||||||
/// # Ok(())
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
#[inline]
|
|
||||||
pub fn merge_filtered(
|
|
||||||
&self,
|
|
||||||
other: &Self,
|
|
||||||
mut filter: impl FnMut(FnAccess, &str, usize) -> bool,
|
|
||||||
) -> Self {
|
|
||||||
let Self(statements, functions) = self;
|
|
||||||
|
|
||||||
let ast = match (statements.is_empty(), other.0.is_empty()) {
|
|
||||||
(false, false) => {
|
|
||||||
let mut statements = statements.clone();
|
|
||||||
statements.extend(other.0.iter().cloned());
|
|
||||||
statements
|
|
||||||
}
|
|
||||||
(false, true) => statements.clone(),
|
|
||||||
(true, false) => other.0.clone(),
|
|
||||||
(true, true) => vec![],
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut functions = functions.clone();
|
|
||||||
functions.merge_filtered(&other.1, &mut filter);
|
|
||||||
|
|
||||||
Self::new(ast, functions)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Combine one `AST` with another. The second `AST` is consumed.
|
|
||||||
///
|
|
||||||
/// Statements in the second `AST` are simply appended to the end of the first _without any processing_.
|
|
||||||
/// Thus, the return value of the first `AST` (if using expression-statement syntax) is buried.
|
|
||||||
/// Of course, if the first `AST` uses a `return` statement at the end, then
|
|
||||||
/// the second `AST` will essentially be dead code.
|
|
||||||
///
|
|
||||||
/// All script-defined functions in the second `AST` are first selected based on a filter
|
|
||||||
/// predicate, then overwrite similarly-named functions in the first `AST` with the
|
|
||||||
/// same number of parameters.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
|
||||||
/// # #[cfg(not(feature = "no_function"))]
|
|
||||||
/// # {
|
|
||||||
/// use rhai::Engine;
|
|
||||||
///
|
|
||||||
/// let engine = Engine::new();
|
|
||||||
///
|
|
||||||
/// let mut ast1 = engine.compile(r#"
|
|
||||||
/// fn foo(x) { 42 + x }
|
|
||||||
/// foo(1)
|
|
||||||
/// "#)?;
|
|
||||||
///
|
|
||||||
/// let ast2 = engine.compile(r#"
|
|
||||||
/// fn foo(n) { "hello" + n }
|
|
||||||
/// fn error() { 0 }
|
|
||||||
/// foo("!")
|
|
||||||
/// "#)?;
|
|
||||||
///
|
|
||||||
/// // Combine 'ast2', picking only 'error()' but not 'foo(_)', into 'ast1'
|
|
||||||
/// ast1.combine_filtered(ast2, |_, name, params| name == "error" && params == 0);
|
|
||||||
///
|
|
||||||
/// // 'ast1' is essentially:
|
|
||||||
/// //
|
|
||||||
/// // fn foo(n) { 42 + n } // <- definition of 'ast1::foo' is not overwritten
|
|
||||||
/// // // because 'ast2::foo' is filtered away
|
|
||||||
/// // foo(1) // <- notice this will be 43 instead of "hello1",
|
|
||||||
/// // // but it is no longer the return value
|
|
||||||
/// // fn error() { 0 } // <- this function passes the filter and is merged
|
|
||||||
/// // foo("!") // <- returns "42!"
|
|
||||||
///
|
|
||||||
/// // Evaluate it
|
|
||||||
/// assert_eq!(engine.eval_ast::<String>(&ast1)?, "42!");
|
|
||||||
/// # }
|
|
||||||
/// # Ok(())
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn combine_filtered(
|
|
||||||
&mut self,
|
|
||||||
other: Self,
|
|
||||||
mut filter: impl FnMut(FnAccess, &str, usize) -> bool,
|
|
||||||
) -> &mut Self {
|
|
||||||
let Self(ref mut statements, ref mut functions) = self;
|
|
||||||
statements.extend(other.0.into_iter());
|
|
||||||
functions.merge_filtered(&other.1, &mut filter);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Filter out the functions, retaining only some based on a filter predicate.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
|
||||||
/// # #[cfg(not(feature = "no_function"))]
|
|
||||||
/// # {
|
|
||||||
/// use rhai::Engine;
|
|
||||||
///
|
|
||||||
/// let engine = Engine::new();
|
|
||||||
///
|
|
||||||
/// let mut ast = engine.compile(r#"
|
|
||||||
/// fn foo(n) { n + 1 }
|
|
||||||
/// fn bar() { print("hello"); }
|
|
||||||
/// "#)?;
|
|
||||||
///
|
|
||||||
/// // Remove all functions except 'foo(_)'
|
|
||||||
/// ast.retain_functions(|_, name, params| name == "foo" && params == 1);
|
|
||||||
/// # }
|
|
||||||
/// # Ok(())
|
|
||||||
/// # }
|
|
||||||
/// ```
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn retain_functions(&mut self, filter: impl FnMut(FnAccess, &str, usize) -> bool) {
|
|
||||||
self.1.retain_functions(filter);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Iterate through all functions
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn iter_functions<'a>(
|
|
||||||
&'a self,
|
|
||||||
) -> impl Iterator<Item = (FnAccess, &str, usize, Shared<ScriptFnDef>)> + 'a {
|
|
||||||
self.1.iter_script_fn()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Clear all function definitions in the `AST`.
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn clear_functions(&mut self) {
|
|
||||||
self.1 = Default::default();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Clear all statements in the `AST`, leaving only function definitions.
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn clear_statements(&mut self) {
|
|
||||||
self.0 = vec![];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<A: AsRef<AST>> Add<A> for &AST {
|
|
||||||
type Output = AST;
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn add(self, rhs: A) -> Self::Output {
|
|
||||||
self.merge(rhs.as_ref())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<A: Into<AST>> AddAssign<A> for AST {
|
|
||||||
#[inline(always)]
|
|
||||||
fn add_assign(&mut self, rhs: A) {
|
|
||||||
self.combine(rhs.into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AsRef<[Stmt]> for AST {
|
|
||||||
#[inline(always)]
|
|
||||||
fn as_ref(&self) -> &[Stmt] {
|
|
||||||
self.statements()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AsRef<Module> for AST {
|
|
||||||
#[inline(always)]
|
|
||||||
fn as_ref(&self) -> &Module {
|
|
||||||
self.lib()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A type representing the access mode of a scripted function.
|
/// A type representing the access mode of a scripted function.
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
|
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
|
||||||
pub enum FnAccess {
|
pub enum FnAccess {
|
||||||
@ -556,9 +140,10 @@ impl fmt::Display for ScriptFnDef {
|
|||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"{}{}({})",
|
"{}{}({})",
|
||||||
match self.access {
|
if self.access.is_private() {
|
||||||
FnAccess::Public => "",
|
"private "
|
||||||
FnAccess::Private => "private ",
|
} else {
|
||||||
|
""
|
||||||
},
|
},
|
||||||
self.name,
|
self.name,
|
||||||
self.params
|
self.params
|
||||||
@ -1488,10 +1073,10 @@ fn parse_fn_call(
|
|||||||
// zero number of arguments, and the actual list of argument `TypeId`'s.
|
// zero number of arguments, and the actual list of argument `TypeId`'s.
|
||||||
// 3) The final hash is the XOR of the two hashes.
|
// 3) The final hash is the XOR of the two hashes.
|
||||||
let qualifiers = modules.iter().map(|(m, _)| m.as_str());
|
let qualifiers = modules.iter().map(|(m, _)| m.as_str());
|
||||||
calc_fn_hash(qualifiers, &id, 0, empty())
|
calc_script_fn_hash(qualifiers, &id, 0)
|
||||||
} else {
|
} else {
|
||||||
// Qualifiers (none) + function name + no parameters.
|
// Qualifiers (none) + function name + no parameters.
|
||||||
calc_fn_hash(empty(), &id, 0, empty())
|
calc_script_fn_hash(empty(), &id, 0)
|
||||||
};
|
};
|
||||||
|
|
||||||
return Ok(Expr::FnCall(Box::new((
|
return Ok(Expr::FnCall(Box::new((
|
||||||
@ -1531,10 +1116,10 @@ fn parse_fn_call(
|
|||||||
// zero number of arguments, and the actual list of argument `TypeId`'s.
|
// zero number of arguments, and the actual list of argument `TypeId`'s.
|
||||||
// 3) The final hash is the XOR of the two hashes.
|
// 3) The final hash is the XOR of the two hashes.
|
||||||
let qualifiers = modules.iter().map(|(m, _)| m.as_str());
|
let qualifiers = modules.iter().map(|(m, _)| m.as_str());
|
||||||
calc_fn_hash(qualifiers, &id, args.len(), empty())
|
calc_script_fn_hash(qualifiers, &id, args.len())
|
||||||
} else {
|
} else {
|
||||||
// Qualifiers (none) + function name + number of arguments.
|
// Qualifiers (none) + function name + number of arguments.
|
||||||
calc_fn_hash(empty(), &id, args.len(), empty())
|
calc_script_fn_hash(empty(), &id, args.len())
|
||||||
};
|
};
|
||||||
|
|
||||||
return Ok(Expr::FnCall(Box::new((
|
return Ok(Expr::FnCall(Box::new((
|
||||||
@ -2108,7 +1693,7 @@ fn parse_primary(
|
|||||||
let modules = modules.as_mut().unwrap();
|
let modules = modules.as_mut().unwrap();
|
||||||
|
|
||||||
// Qualifiers + variable name
|
// Qualifiers + variable name
|
||||||
*hash = calc_fn_hash(modules.iter().map(|(v, _)| v.as_str()), name, 0, empty());
|
*hash = calc_script_fn_hash(modules.iter().map(|(v, _)| v.as_str()), name, 0);
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
modules.set_index(state.find_module(&modules[0].0));
|
modules.set_index(state.find_module(&modules[0].0));
|
||||||
@ -2171,7 +1756,7 @@ fn parse_unary(
|
|||||||
// Call negative function
|
// Call negative function
|
||||||
expr => {
|
expr => {
|
||||||
let op = "-";
|
let op = "-";
|
||||||
let hash = calc_fn_hash(empty(), op, 1, empty());
|
let hash = calc_script_fn_hash(empty(), op, 1);
|
||||||
let mut args = StaticVec::new();
|
let mut args = StaticVec::new();
|
||||||
args.push(expr);
|
args.push(expr);
|
||||||
|
|
||||||
@ -2198,7 +1783,7 @@ fn parse_unary(
|
|||||||
args.push(expr);
|
args.push(expr);
|
||||||
|
|
||||||
let op = "!";
|
let op = "!";
|
||||||
let hash = calc_fn_hash(empty(), op, 1, empty());
|
let hash = calc_script_fn_hash(empty(), op, 1);
|
||||||
|
|
||||||
Ok(Expr::FnCall(Box::new((
|
Ok(Expr::FnCall(Box::new((
|
||||||
(op.into(), true, false, pos),
|
(op.into(), true, false, pos),
|
||||||
@ -2238,7 +1823,7 @@ fn parse_unary(
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Qualifiers (none) + function name + number of arguments.
|
// Qualifiers (none) + function name + number of arguments.
|
||||||
let hash = calc_fn_hash(empty(), &func.name, func.params.len(), empty());
|
let hash = calc_script_fn_hash(empty(), &func.name, func.params.len());
|
||||||
|
|
||||||
lib.insert(hash, func);
|
lib.insert(hash, func);
|
||||||
|
|
||||||
@ -2671,7 +2256,7 @@ fn parse_binary_op(
|
|||||||
|
|
||||||
let cmp_def = Some(false);
|
let cmp_def = Some(false);
|
||||||
let op = op_token.syntax();
|
let op = op_token.syntax();
|
||||||
let hash = calc_fn_hash(empty(), &op, 2, empty());
|
let hash = calc_script_fn_hash(empty(), &op, 2);
|
||||||
let op = (op, true, false, pos);
|
let op = (op, true, false, pos);
|
||||||
|
|
||||||
let mut args = StaticVec::new();
|
let mut args = StaticVec::new();
|
||||||
@ -3377,7 +2962,7 @@ fn parse_stmt(
|
|||||||
let func = parse_fn(input, &mut new_state, lib, access, settings)?;
|
let func = parse_fn(input, &mut new_state, lib, access, settings)?;
|
||||||
|
|
||||||
// Qualifiers (none) + function name + number of arguments.
|
// Qualifiers (none) + function name + number of arguments.
|
||||||
let hash = calc_fn_hash(empty(), &func.name, func.params.len(), empty());
|
let hash = calc_script_fn_hash(empty(), &func.name, func.params.len());
|
||||||
|
|
||||||
lib.insert(hash, func);
|
lib.insert(hash, func);
|
||||||
|
|
||||||
@ -3654,7 +3239,7 @@ fn make_curry_from_externals(fn_expr: Expr, externals: StaticVec<Ident>, pos: Po
|
|||||||
args.push(Expr::Variable(Box::new((x.clone(), None, 0, None))));
|
args.push(Expr::Variable(Box::new((x.clone(), None, 0, None))));
|
||||||
});
|
});
|
||||||
|
|
||||||
let hash = calc_fn_hash(empty(), KEYWORD_FN_PTR_CURRY, num_externals + 1, empty());
|
let hash = calc_script_fn_hash(empty(), KEYWORD_FN_PTR_CURRY, num_externals + 1);
|
||||||
|
|
||||||
let expr = Expr::FnCall(Box::new((
|
let expr = Expr::FnCall(Box::new((
|
||||||
(KEYWORD_FN_PTR_CURRY.into(), false, false, pos),
|
(KEYWORD_FN_PTR_CURRY.into(), false, false, pos),
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//! Module defining macros for developing _plugins_.
|
//! Module defining macros for developing _plugins_.
|
||||||
|
|
||||||
pub use crate::any::Dynamic;
|
pub use crate::dynamic::Dynamic;
|
||||||
pub use crate::engine::Engine;
|
pub use crate::engine::Engine;
|
||||||
pub use crate::fn_native::{CallableFunction, FnCallArgs, NativeCallContext};
|
pub use crate::fn_native::{CallableFunction, FnCallArgs, NativeCallContext};
|
||||||
pub use crate::fn_register::{RegisterFn, RegisterResultFn};
|
pub use crate::fn_register::{RegisterFn, RegisterResultFn};
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
//! Module containing error definitions for the evaluation process.
|
//! Module containing error definitions for the evaluation process.
|
||||||
|
|
||||||
use crate::any::Dynamic;
|
use crate::dynamic::Dynamic;
|
||||||
use crate::error::ParseErrorType;
|
use crate::parse_error::ParseErrorType;
|
||||||
use crate::parser::INT;
|
use crate::parser::INT;
|
||||||
use crate::token::Position;
|
use crate::token::Position;
|
||||||
use crate::utils::ImmutableString;
|
use crate::utils::ImmutableString;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//! Module that defines the `Scope` type representing a function call-stack scope.
|
//! Module that defines the `Scope` type representing a function call-stack scope.
|
||||||
|
|
||||||
use crate::any::{Dynamic, Variant};
|
use crate::dynamic::{Dynamic, Variant};
|
||||||
use crate::parser::{map_dynamic_to_expr, Expr};
|
use crate::parser::{map_dynamic_to_expr, Expr};
|
||||||
use crate::token::Position;
|
use crate::token::Position;
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
//! Implement deserialization support of `Dynamic` for [`serde`](https://crates.io/crates/serde).
|
//! Implement deserialization support of `Dynamic` for [`serde`](https://crates.io/crates/serde).
|
||||||
|
|
||||||
use super::str::ImmutableStringDeserializer;
|
use super::str::ImmutableStringDeserializer;
|
||||||
use crate::any::{Dynamic, Union};
|
use crate::dynamic::{Dynamic, Union};
|
||||||
use crate::error::ParseErrorType;
|
use crate::parse_error::ParseErrorType;
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::token::Position;
|
use crate::token::Position;
|
||||||
use crate::utils::ImmutableString;
|
use crate::utils::ImmutableString;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//! Implement serialization support of `Dynamic` for [`serde`](https://crates.io/crates/serde).
|
//! Implement serialization support of `Dynamic` for [`serde`](https://crates.io/crates/serde).
|
||||||
|
|
||||||
use crate::any::Dynamic;
|
use crate::dynamic::Dynamic;
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::token::Position;
|
use crate::token::Position;
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
//! Module implementing custom syntax for `Engine`.
|
//! Module implementing custom syntax for `Engine`.
|
||||||
|
|
||||||
use crate::any::Dynamic;
|
use crate::dynamic::Dynamic;
|
||||||
use crate::engine::{Engine, EvalContext, MARKER_BLOCK, MARKER_EXPR, MARKER_IDENT};
|
use crate::engine::{Engine, EvalContext, MARKER_BLOCK, MARKER_EXPR, MARKER_IDENT};
|
||||||
use crate::error::{LexError, ParseError};
|
|
||||||
use crate::fn_native::{SendSync, Shared};
|
use crate::fn_native::{SendSync, Shared};
|
||||||
|
use crate::parse_error::{LexError, ParseError};
|
||||||
use crate::parser::Expr;
|
use crate::parser::Expr;
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::token::{is_valid_identifier, Position, Token};
|
use crate::token::{is_valid_identifier, Position, Token};
|
||||||
|
@ -8,7 +8,7 @@ use crate::engine::{
|
|||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
use crate::engine::KEYWORD_IS_SHARED;
|
use crate::engine::KEYWORD_IS_SHARED;
|
||||||
|
|
||||||
use crate::error::LexError;
|
use crate::parse_error::LexError;
|
||||||
use crate::parser::INT;
|
use crate::parser::INT;
|
||||||
use crate::StaticVec;
|
use crate::StaticVec;
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//! A helper module containing unsafe utility functions.
|
//! A helper module containing unsafe utility functions.
|
||||||
|
|
||||||
use crate::any::Variant;
|
use crate::dynamic::Variant;
|
||||||
|
|
||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
any::{Any, TypeId},
|
any::{Any, TypeId},
|
||||||
|
59
src/utils.rs
59
src/utils.rs
@ -9,7 +9,7 @@ use crate::stdlib::{
|
|||||||
cmp::Ordering,
|
cmp::Ordering,
|
||||||
fmt,
|
fmt,
|
||||||
hash::{BuildHasher, Hash, Hasher},
|
hash::{BuildHasher, Hash, Hasher},
|
||||||
iter::FromIterator,
|
iter::{empty, FromIterator},
|
||||||
ops::{Add, AddAssign, Deref},
|
ops::{Add, AddAssign, Deref},
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
string::{String, ToString},
|
string::{String, ToString},
|
||||||
@ -72,22 +72,69 @@ impl BuildHasher for StraightHasherBuilder {
|
|||||||
/// # Note
|
/// # Note
|
||||||
///
|
///
|
||||||
/// The first module name is skipped. Hashing starts from the _second_ module in the chain.
|
/// The first module name is skipped. Hashing starts from the _second_ module in the chain.
|
||||||
pub fn calc_fn_hash<'a>(
|
#[inline(always)]
|
||||||
|
pub fn calc_native_fn_hash<'a>(
|
||||||
|
modules: impl Iterator<Item = &'a str>,
|
||||||
|
fn_name: &str,
|
||||||
|
params: impl Iterator<Item = TypeId>,
|
||||||
|
) -> u64 {
|
||||||
|
calc_fn_hash(modules, fn_name, None, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// _[INTERNALS]_ Calculate a `u64` hash key from a module-qualified function name and the number of parameters,
|
||||||
|
/// but no parameter types.
|
||||||
|
/// Exported under the `internals` feature only.
|
||||||
|
///
|
||||||
|
/// Module names are passed in via `&str` references from an iterator.
|
||||||
|
/// Parameter types are passed in via `TypeId` values from an iterator.
|
||||||
|
///
|
||||||
|
/// # Note
|
||||||
|
///
|
||||||
|
/// The first module name is skipped. Hashing starts from the _second_ module in the chain.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn calc_script_fn_hash<'a>(
|
||||||
modules: impl Iterator<Item = &'a str>,
|
modules: impl Iterator<Item = &'a str>,
|
||||||
fn_name: &str,
|
fn_name: &str,
|
||||||
num: usize,
|
num: usize,
|
||||||
|
) -> u64 {
|
||||||
|
calc_fn_hash(modules, fn_name, Some(num), empty())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Calculate a `u64` hash key from a module-qualified function name and parameter types.
|
||||||
|
///
|
||||||
|
/// Module names are passed in via `&str` references from an iterator.
|
||||||
|
/// Parameter types are passed in via `TypeId` values from an iterator.
|
||||||
|
///
|
||||||
|
/// # Note
|
||||||
|
///
|
||||||
|
/// The first module name is skipped. Hashing starts from the _second_ module in the chain.
|
||||||
|
fn calc_fn_hash<'a>(
|
||||||
|
modules: impl Iterator<Item = &'a str>,
|
||||||
|
fn_name: &str,
|
||||||
|
num: Option<usize>,
|
||||||
params: impl Iterator<Item = TypeId>,
|
params: impl Iterator<Item = TypeId>,
|
||||||
) -> u64 {
|
) -> u64 {
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
let mut s: AHasher = Default::default();
|
let s: &mut AHasher = &mut Default::default();
|
||||||
#[cfg(not(feature = "no_std"))]
|
#[cfg(not(feature = "no_std"))]
|
||||||
let mut s = DefaultHasher::new();
|
let s = &mut DefaultHasher::new();
|
||||||
|
|
||||||
// We always skip the first module
|
// We always skip the first module
|
||||||
modules.skip(1).for_each(|m| m.hash(&mut s));
|
modules.skip(1).for_each(|m| m.hash(s));
|
||||||
s.write(fn_name.as_bytes());
|
s.write(fn_name.as_bytes());
|
||||||
|
let num = if let Some(num) = num {
|
||||||
|
num
|
||||||
|
} else {
|
||||||
|
let mut count = 0;
|
||||||
|
|
||||||
|
params.for_each(|t| {
|
||||||
|
count += 1;
|
||||||
|
t.hash(s);
|
||||||
|
});
|
||||||
|
|
||||||
|
count
|
||||||
|
};
|
||||||
s.write_usize(num);
|
s.write_usize(num);
|
||||||
params.for_each(|t| t.hash(&mut s));
|
|
||||||
s.finish()
|
s.finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user