Merge pull request #272 from schungx/master

Code refactor.
This commit is contained in:
Stephen Chung 2020-10-29 12:11:31 +08:00 committed by GitHub
commit 45effc6276
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 1635 additions and 1534 deletions

View File

@ -5,7 +5,9 @@ Rhai Release Notes
Version 0.19.4 Version 0.19.4
============== ==============
This version adds a low-level API for more flexibility when defining custom syntax. This version basically cleans up the code structure in preparation for a potential `1.0` release in the future.
This version also adds a low-level API for more flexibility when defining custom syntax.
Bug fixes Bug fixes
--------- ---------
@ -24,6 +26,11 @@ New features
* Low-level API for custom syntax allowing more flexibility in designing the syntax. * Low-level API for custom syntax allowing more flexibility in designing the syntax.
* `Module::fill_with` to poly-fill a module with another. * `Module::fill_with` to poly-fill a module with another.
Enhancements
------------
* AST data structures are optimized to maximize cache friendliness. This may have speed impacts on large, complex scripts (benchmarks wanted!).
Version 0.19.3 Version 0.19.3
============== ==============

View File

@ -4,7 +4,7 @@ error[E0277]: the trait bound `NonClonable: Clone` is not satisfied
11 | pub fn test_fn(input: f32) -> NonClonable { 11 | pub fn test_fn(input: f32) -> NonClonable {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `NonClonable` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `NonClonable`
| |
::: $WORKSPACE/src/any.rs ::: $WORKSPACE/src/dynamic.rs
| |
| pub fn from<T: Variant + Clone>(value: T) -> Self { | pub fn from<T: Variant + Clone>(value: T) -> Self {
| ----- required by this bound in `rhai::Dynamic::from` | ----- required by this bound in `rhai::Dynamic::from`

View File

@ -4,7 +4,7 @@ error[E0277]: the trait bound `NonClonable: Clone` is not satisfied
12 | pub fn test_fn(input: f32) -> NonClonable { 12 | pub fn test_fn(input: f32) -> NonClonable {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `NonClonable` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `NonClonable`
| |
::: $WORKSPACE/src/any.rs ::: $WORKSPACE/src/dynamic.rs
| |
| pub fn from<T: Variant + Clone>(value: T) -> Self { | pub fn from<T: Variant + Clone>(value: T) -> Self {
| ----- required by this bound in `rhai::Dynamic::from` | ----- required by this bound in `rhai::Dynamic::from`

1226
src/ast.rs Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,14 +1,15 @@
//! Helper module which defines the `Any` trait to to allow dynamic value handling. //! Helper module which defines the `Any` trait to to allow dynamic value handling.
use crate::fn_native::{FnPtr, SendSync}; use crate::fn_native::{FnPtr, SendSync};
use crate::parser::{ImmutableString, INT};
use crate::r#unsafe::{unsafe_cast_box, unsafe_try_cast}; use crate::r#unsafe::{unsafe_cast_box, unsafe_try_cast};
use crate::utils::ImmutableString;
use crate::INT;
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
use crate::fn_native::{shared_try_take, Locked, Shared}; use crate::fn_native::{shared_try_take, Locked, Shared};
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
use crate::parser::FLOAT; use crate::FLOAT;
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
use crate::engine::Array; use crate::engine::Array;

View File

@ -1,21 +1,21 @@
//! 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::ast::{BinaryExpr, Expr, Ident, ReturnType, Stmt};
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};
use crate::optimize::OptimizationLevel; use crate::optimize::OptimizationLevel;
use crate::packages::{Package, PackagesCollection, StandardPackage}; use crate::packages::{Package, PackagesCollection, StandardPackage};
use crate::parser::{BinaryExpr, Expr, ReturnType, Stmt};
use crate::r#unsafe::unsafe_cast_var_name_to_lifetime; use crate::r#unsafe::unsafe_cast_var_name_to_lifetime;
use crate::result::EvalAltResult; 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::INT;
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
use crate::module::ModuleResolver; use crate::module::ModuleResolver;
@ -29,10 +29,11 @@ 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,
borrow::Cow,
boxed::Box, boxed::Box,
collections::{HashMap, HashSet}, collections::{HashMap, HashSet},
fmt, format, fmt, format,
@ -388,10 +389,10 @@ pub struct State {
} }
impl State { impl State {
/// Create a new `State`. /// Is the state currently at global (root) level?
#[inline(always)] #[inline(always)]
pub fn new() -> Self { pub fn is_global(&self) -> bool {
Default::default() self.scope_level == 0
} }
} }
@ -455,7 +456,7 @@ impl<'e, 'x, 'px, 'a, 's, 'm, 'pm, 't, 'pt> EvalContext<'e, 'x, 'px, 'a, 's, 'm,
#[cfg(feature = "internals")] #[cfg(feature = "internals")]
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
#[inline(always)] #[inline(always)]
pub fn imports(&self) -> &'a Imports { pub fn imports(&'a self) -> &'a Imports {
self.mods self.mods
} }
/// 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.
@ -764,7 +765,7 @@ impl Engine {
match expr { match expr {
Expr::Variable(v) => match v.as_ref() { Expr::Variable(v) => match v.as_ref() {
// Qualified variable // Qualified variable
((name, pos), Some(modules), hash_var, _) => { (Ident { name, pos }, Some(modules), hash_var, _) => {
let module = search_imports_mut(mods, state, modules)?; let module = search_imports_mut(mods, state, modules)?;
let target = module.get_qualified_var_mut(*hash_var).map_err(|mut err| { let target = module.get_qualified_var_mut(*hash_var).map_err(|mut err| {
match *err { match *err {
@ -796,7 +797,7 @@ impl Engine {
this_ptr: &'s mut Option<&mut Dynamic>, this_ptr: &'s mut Option<&mut Dynamic>,
expr: &'a Expr, expr: &'a Expr,
) -> Result<(Target<'s>, &'a str, ScopeEntryType, Position), Box<EvalAltResult>> { ) -> Result<(Target<'s>, &'a str, ScopeEntryType, Position), Box<EvalAltResult>> {
let ((name, pos), _, _, index) = match expr { let (Ident { name, pos }, _, _, index) = match expr {
Expr::Variable(v) => v.as_ref(), Expr::Variable(v) => v.as_ref(),
_ => unreachable!(), _ => unreachable!(),
}; };
@ -1187,7 +1188,10 @@ impl Engine {
match dot_lhs { match dot_lhs {
// id.??? or id[???] // id.??? or id[???]
Expr::Variable(x) => { Expr::Variable(x) => {
let (var_name, var_pos) = &x.0; let Ident {
name: var_name,
pos: var_pos,
} = &x.0;
self.inc_operations(state) self.inc_operations(state)
.map_err(|err| err.fill_position(*var_pos))?; .map_err(|err| err.fill_position(*var_pos))?;
@ -1438,8 +1442,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)
@ -1491,14 +1494,16 @@ impl Engine {
Expr::IntegerConstant(x) => Ok(x.0.into()), Expr::IntegerConstant(x) => Ok(x.0.into()),
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
Expr::FloatConstant(x) => Ok(x.0.into()), Expr::FloatConstant(x) => Ok(x.0.into()),
Expr::StringConstant(x) => Ok(x.0.to_string().into()), Expr::StringConstant(x) => Ok(x.name.to_string().into()),
Expr::CharConstant(x) => Ok(x.0.into()), Expr::CharConstant(x) => Ok(x.0.into()),
Expr::FnPointer(x) => Ok(FnPtr::new_unchecked(x.0.clone(), Default::default()).into()), Expr::FnPointer(x) => {
Expr::Variable(x) if (x.0).0 == KEYWORD_THIS => { Ok(FnPtr::new_unchecked(x.name.clone(), Default::default()).into())
}
Expr::Variable(x) if (x.0).name == KEYWORD_THIS => {
if let Some(val) = this_ptr { if let Some(val) = this_ptr {
Ok(val.clone()) Ok(val.clone())
} else { } else {
EvalAltResult::ErrorUnboundThis((x.0).1).into() EvalAltResult::ErrorUnboundThis((x.0).pos).into()
} }
} }
Expr::Variable(_) => { Expr::Variable(_) => {
@ -1533,9 +1538,9 @@ impl Engine {
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
Expr::Map(x) => Ok(Dynamic(Union::Map(Box::new( Expr::Map(x) => Ok(Dynamic(Union::Map(Box::new(
x.0.iter() x.0.iter()
.map(|((key, _), expr)| { .map(|(key, expr)| {
self.eval_expr(scope, mods, state, lib, this_ptr, expr, level) self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)
.map(|val| (key.clone(), val)) .map(|val| (key.name.clone(), val))
}) })
.collect::<Result<HashMap<_, _>, _>>()?, .collect::<Result<HashMap<_, _>, _>>()?,
)))), )))),
@ -1687,7 +1692,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
@ -1885,7 +1890,11 @@ impl Engine {
if let Some(func) = func { if let Some(func) = func {
// Add the loop variable // Add the loop variable
let var_name = unsafe_cast_var_name_to_lifetime(name, &state); let var_name: Cow<'_, str> = if state.is_global() {
name.clone().into()
} else {
unsafe_cast_var_name_to_lifetime(name).into()
};
scope.push(var_name, ()); scope.push(var_name, ());
let index = scope.len() - 1; let index = scope.len() - 1;
state.scope_level += 1; state.scope_level += 1;
@ -1929,7 +1938,7 @@ impl Engine {
// Try/Catch statement // Try/Catch statement
Stmt::TryCatch(x) => { Stmt::TryCatch(x) => {
let ((try_body, _), var_def, (catch_body, _)) = x.as_ref(); let (try_body, var_def, catch_body, _) = x.as_ref();
let result = self let result = self
.eval_stmt(scope, mods, state, lib, this_ptr, try_body, level) .eval_stmt(scope, mods, state, lib, this_ptr, try_body, level)
@ -1951,8 +1960,12 @@ impl Engine {
let orig_scope_len = scope.len(); let orig_scope_len = scope.len();
state.scope_level += 1; state.scope_level += 1;
if let Some((var_name, _)) = var_def { if let Some(Ident { name, .. }) = var_def {
let var_name = unsafe_cast_var_name_to_lifetime(var_name, &state); let var_name: Cow<'_, str> = if state.is_global() {
name.clone().into()
} else {
unsafe_cast_var_name_to_lifetime(name).into()
};
scope.push(var_name, value); scope.push(var_name, value);
} }
@ -2016,7 +2029,11 @@ impl Engine {
} else { } else {
().into() ().into()
}; };
let var_name = unsafe_cast_var_name_to_lifetime(&var_def.0, &state); let var_name: Cow<'_, str> = if state.is_global() {
var_def.name.clone().into()
} else {
unsafe_cast_var_name_to_lifetime(&var_def.name).into()
};
scope.push_dynamic_value(var_name, entry_type, val, false); scope.push_dynamic_value(var_name, entry_type, val, false);
Ok(Default::default()) Ok(Default::default())
} }
@ -2039,7 +2056,7 @@ impl Engine {
if let Some(name_def) = alias { if let Some(name_def) = alias {
module.index_all_sub_modules(); module.index_all_sub_modules();
mods.push((name_def.0.clone(), module)); mods.push((name_def.name.clone(), module));
} }
state.modules += 1; state.modules += 1;
@ -2059,13 +2076,13 @@ impl Engine {
// Export statement // Export statement
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
Stmt::Export(list, _) => { Stmt::Export(list, _) => {
for ((id, id_pos), rename) in list.iter() { for (Ident { name, pos: id_pos }, rename) in list.iter() {
// Mark scope variables as public // Mark scope variables as public
if let Some(index) = scope.get_index(id).map(|(i, _)| i) { if let Some(index) = scope.get_index(name).map(|(i, _)| i) {
let alias = rename.as_ref().map(|(n, _)| n).unwrap_or_else(|| id); let alias = rename.as_ref().map(|x| &x.name).unwrap_or_else(|| name);
scope.set_entry_alias(index, alias.clone()); scope.set_entry_alias(index, alias.clone());
} else { } else {
return EvalAltResult::ErrorVariableNotFound(id.into(), *id_pos).into(); return EvalAltResult::ErrorVariableNotFound(name.into(), *id_pos).into();
} }
} }
Ok(Default::default()) Ok(Default::default())
@ -2073,7 +2090,7 @@ impl Engine {
// Share statement // Share statement
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
Stmt::Share(var_name, _) => { Stmt::Share(Ident { name: var_name, .. }) => {
match scope.get_index(var_name) { match scope.get_index(var_name) {
Some((index, ScopeEntryType::Normal)) => { Some((index, ScopeEntryType::Normal)) => {
let (val, _) = scope.get_mut(index); let (val, _) = scope.get_mut(index);

View File

@ -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::engine::{Engine, EvalContext, Imports, State}; use crate::dynamic::{Dynamic, Variant};
use crate::error::ParseError; use crate::engine::{Engine, EvalContext, Imports};
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,
}; };
@ -1619,7 +1619,7 @@ impl Engine {
.get_script_fn(name, args.len(), true) .get_script_fn(name, args.len(), true)
.ok_or_else(|| EvalAltResult::ErrorFunctionNotFound(name.into(), Position::none()))?; .ok_or_else(|| EvalAltResult::ErrorFunctionNotFound(name.into(), Position::none()))?;
let mut state = State::new(); let mut state = Default::default();
let mut mods = Default::default(); let mut mods = Default::default();
// Check for data race. // Check for data race.

View File

@ -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.

View File

@ -1,30 +1,31 @@
//! Implement function-calling mechanism for `Engine`. //! Implement function-calling mechanism for `Engine`.
use crate::any::Dynamic; use crate::ast::{Expr, Stmt};
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::parser::{Expr, ImmutableString, Stmt, INT}; use crate::parse_error::ParseErrorType;
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::utils::ImmutableString;
use crate::{calc_native_fn_hash, calc_script_fn_hash, StaticVec, INT};
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
use crate::{ use crate::{
parser::ScriptFnDef, r#unsafe::unsafe_cast_var_name_to_lifetime, ast::ScriptFnDef, r#unsafe::unsafe_cast_var_name_to_lifetime,
scope::EntryType as ScopeEntryType, scope::EntryType as ScopeEntryType,
}; };
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
use crate::parser::FLOAT; use crate::FLOAT;
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
use crate::engine::{FN_IDX_GET, FN_IDX_SET}; use crate::engine::{FN_IDX_GET, FN_IDX_SET};
@ -50,6 +51,9 @@ use crate::stdlib::{
vec::Vec, vec::Vec,
}; };
#[cfg(not(feature = "no_function"))]
use crate::stdlib::borrow::Cow;
#[cfg(feature = "no_std")] #[cfg(feature = "no_std")]
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
use num_traits::float::Float; use num_traits::float::Float;
@ -376,7 +380,7 @@ impl Engine {
.iter() .iter()
.zip(args.iter_mut().map(|v| mem::take(*v))) .zip(args.iter_mut().map(|v| mem::take(*v)))
.map(|(name, value)| { .map(|(name, value)| {
let var_name = unsafe_cast_var_name_to_lifetime(name.as_str(), state); let var_name: Cow<'_, str> = unsafe_cast_var_name_to_lifetime(name).into();
(var_name, ScopeEntryType::Normal, value) (var_name, ScopeEntryType::Normal, value)
}), }),
); );
@ -438,15 +442,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)
} }
@ -502,17 +499,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
@ -644,7 +631,7 @@ impl Engine {
statements: impl IntoIterator<Item = &'a Stmt>, statements: impl IntoIterator<Item = &'a Stmt>,
lib: &[&Module], lib: &[&Module],
) -> Result<(Dynamic, u64), Box<EvalAltResult>> { ) -> Result<(Dynamic, u64), Box<EvalAltResult>> {
let mut state = State::new(); let mut state = Default::default();
statements statements
.into_iter() .into_iter()
@ -740,7 +727,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<_>>();
@ -767,7 +754,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<_>>();
@ -830,7 +817,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())
}; };
} }
} }
@ -881,7 +868,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
@ -962,12 +949,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 =
@ -981,10 +968,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(),
@ -1006,7 +992,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());
@ -1015,7 +1001,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
@ -1184,8 +1170,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;

View File

@ -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;

View File

@ -1,14 +1,14 @@
//! Module defining interfaces to native-Rust functions. //! Module defining interfaces to native-Rust functions.
use crate::any::Dynamic; use crate::ast::{FnAccess, ScriptFnDef};
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::plugin::PluginFunction; 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);

View File

@ -2,10 +2,10 @@
#![allow(non_snake_case)] #![allow(non_snake_case)]
use crate::any::{Dynamic, DynamicWriteLock, Variant}; use crate::ast::FnAccess;
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::r#unsafe::unsafe_cast_box; use crate::r#unsafe::unsafe_cast_box;
use crate::result::EvalAltResult; use crate::result::EvalAltResult;
use crate::utils::ImmutableString; use crate::utils::ImmutableString;

View File

@ -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,43 +70,60 @@ 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; /// The system integer type.
///
/// If the `only_i32` feature is enabled, this will be `i32` instead.
#[cfg(not(feature = "only_i32"))]
pub type INT = i64;
/// The system integer type.
///
/// If the `only_i32` feature is not enabled, this will be `i64` instead.
#[cfg(feature = "only_i32")]
pub type INT = i32;
/// The system floating-point type.
///
/// Not available under the `no_float` feature.
#[cfg(not(feature = "no_float"))]
pub type FLOAT = f64;
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 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;
pub use utils::ImmutableString;
#[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::*;
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
pub use parser::FnAccess; pub use ast::FnAccess;
#[cfg(feature = "no_function")]
pub use parser::FnAccess;
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
pub use fn_func::Func; pub use fn_func::Func;
@ -116,9 +134,6 @@ pub use engine::Array;
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
pub use engine::Map; pub use engine::Map;
#[cfg(not(feature = "no_float"))]
pub use parser::FLOAT;
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
pub use module::ModuleResolver; pub use module::ModuleResolver;
@ -141,7 +156,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")]
@ -149,7 +164,9 @@ pub use token::{get_next_token, parse_string_literal, InputStream, Token, Tokeni
#[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 parser::{CustomExpr, Expr, FloatWrapper, ReturnType, ScriptFnDef, Stmt}; pub use ast::{
BinaryExpr, CustomExpr, Expr, FloatWrapper, Ident, IdentX, ReturnType, ScriptFnDef, Stmt,
};
#[cfg(feature = "internals")] #[cfg(feature = "internals")]
#[deprecated(note = "this type is volatile and may change")] #[deprecated(note = "this type is volatile and may change")]

View File

@ -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::ast::FnAccess;
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::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::{ast::ScriptFnDef, fn_native::Shared};
#[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()));
} }

View File

@ -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;

View File

@ -1,22 +1,20 @@
//! Module implementing the AST optimizer. //! Module implementing the AST optimizer.
use crate::any::Dynamic; use crate::ast::{BinaryExpr, CustomExpr, Expr, ScriptFnDef, Stmt, 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, Expr, ScriptFnDef, Stmt, AST}; use crate::parser::map_dynamic_to_expr;
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::ast::ReturnType;
#[cfg(feature = "internals")]
use crate::parser::CustomExpr;
use crate::stdlib::{ use crate::stdlib::{
boxed::Box, boxed::Box,
@ -137,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
@ -283,18 +276,18 @@ fn optimize_stmt(stmt: Stmt, state: &mut State, preserve_result: bool) -> Stmt {
.into_iter() .into_iter()
.map(|stmt| match stmt { .map(|stmt| match stmt {
// Add constant literals into the state // Add constant literals into the state
Stmt::Const(name, Some(expr), pos) if expr.is_literal() => { Stmt::Const(var_def, Some(expr), pos) if expr.is_literal() => {
state.set_dirty(); state.set_dirty();
state.push_constant(&name.0, expr); state.push_constant(&var_def.name, expr);
Stmt::Noop(pos) // No need to keep constants Stmt::Noop(pos) // No need to keep constants
} }
Stmt::Const(name, Some(expr), pos) if expr.is_literal() => { Stmt::Const(var_def, Some(expr), pos) if expr.is_literal() => {
let expr = optimize_expr(expr, state); let expr = optimize_expr(expr, state);
Stmt::Const(name, Some(expr), pos) Stmt::Const(var_def, Some(expr), pos)
} }
Stmt::Const(name, None, pos) => { Stmt::Const(var_def, None, pos) => {
state.set_dirty(); state.set_dirty();
state.push_constant(&name.0, Expr::Unit(name.1)); state.push_constant(&var_def.name, Expr::Unit(var_def.pos));
Stmt::Noop(pos) // No need to keep constants Stmt::Noop(pos) // No need to keep constants
} }
// Optimize the statement // Optimize the statement
@ -389,22 +382,25 @@ fn optimize_stmt(stmt: Stmt, state: &mut State, preserve_result: bool) -> Stmt {
} }
} }
// try { block } catch ( var ) { block } // try { block } catch ( var ) { block }
Stmt::TryCatch(x) if (x.0).0.is_pure() => { Stmt::TryCatch(x) if x.0.is_pure() => {
// If try block is pure, there will never be any exceptions // If try block is pure, there will never be any exceptions
state.set_dirty(); state.set_dirty();
let pos = (x.0).0.position(); let pos = x.0.position();
let mut statements: Vec<_> = Default::default(); let mut statements = match optimize_stmt(x.0, state, preserve_result) {
statements.push(optimize_stmt((x.0).0, state, preserve_result)); Stmt::Block(statements, _) => statements,
stmt => vec![stmt],
};
statements.push(Stmt::Noop(pos)); statements.push(Stmt::Noop(pos));
Stmt::Block(statements, pos) Stmt::Block(statements, pos)
} }
// try { block } catch ( var ) { block } // try { block } catch ( var ) { block }
Stmt::TryCatch(x) => { Stmt::TryCatch(x) => {
let ((try_block, try_pos), var_name, (catch_block, catch_pos)) = *x; let (try_block, var_name, catch_block, pos) = *x;
Stmt::TryCatch(Box::new(( Stmt::TryCatch(Box::new((
(optimize_stmt(try_block, state, false), try_pos), optimize_stmt(try_block, state, false),
var_name, var_name,
(optimize_stmt(catch_block, state, false), catch_pos), optimize_stmt(catch_block, state, false),
pos,
))) )))
} }
// expr; // expr;
@ -463,7 +459,7 @@ fn optimize_expr(expr: Expr, state: &mut State) -> Expr {
// All other items can be thrown away. // All other items can be thrown away.
state.set_dirty(); state.set_dirty();
let pos = m.1; let pos = m.1;
m.0.into_iter().find(|((name, _), _)| name == prop) m.0.into_iter().find(|(x, _)| &x.name == prop)
.map(|(_, mut expr)| { expr.set_position(pos); expr }) .map(|(_, mut expr)| { expr.set_position(pos); expr })
.unwrap_or_else(|| Expr::Unit(pos)) .unwrap_or_else(|| Expr::Unit(pos))
} }
@ -495,15 +491,15 @@ fn optimize_expr(expr: Expr, state: &mut State) -> Expr {
// All other items can be thrown away. // All other items can be thrown away.
state.set_dirty(); state.set_dirty();
let pos = m.1; let pos = m.1;
m.0.into_iter().find(|((name, _), _)| *name == s.0) m.0.into_iter().find(|(x, _)| x.name == s.name)
.map(|(_, mut expr)| { expr.set_position(pos); expr }) .map(|(_, mut expr)| { expr.set_position(pos); expr })
.unwrap_or_else(|| Expr::Unit(pos)) .unwrap_or_else(|| Expr::Unit(pos))
} }
// string[int] // string[int]
(Expr::StringConstant(s), Expr::IntegerConstant(i)) if i.0 >= 0 && (i.0 as usize) < s.0.chars().count() => { (Expr::StringConstant(s), Expr::IntegerConstant(i)) if i.0 >= 0 && (i.0 as usize) < s.name.chars().count() => {
// String literal indexing - get the character // String literal indexing - get the character
state.set_dirty(); state.set_dirty();
Expr::CharConstant(Box::new((s.0.chars().nth(i.0 as usize).unwrap(), s.1))) Expr::CharConstant(Box::new((s.name.chars().nth(i.0 as usize).unwrap(), s.pos)))
} }
// lhs[rhs] // lhs[rhs]
(lhs, rhs) => Expr::Index(Box::new(BinaryExpr { (lhs, rhs) => Expr::Index(Box::new(BinaryExpr {
@ -520,27 +516,27 @@ fn optimize_expr(expr: Expr, state: &mut State) -> Expr {
// [ items .. ] // [ items .. ]
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
Expr::Map(m) => Expr::Map(Box::new((m.0 Expr::Map(m) => Expr::Map(Box::new((m.0
.into_iter().map(|((key, pos), expr)| ((key, pos), optimize_expr(expr, state))) .into_iter().map(|(key, expr)| (key, optimize_expr(expr, state)))
.collect(), m.1))), .collect(), m.1))),
// lhs in rhs // lhs in rhs
Expr::In(x) => match (x.lhs, x.rhs) { Expr::In(x) => match (x.lhs, x.rhs) {
// "xxx" in "xxxxx" // "xxx" in "xxxxx"
(Expr::StringConstant(a), Expr::StringConstant(b)) => { (Expr::StringConstant(a), Expr::StringConstant(b)) => {
state.set_dirty(); state.set_dirty();
if b.0.contains(a.0.as_str()) { Expr::True(a.1) } else { Expr::False(a.1) } if b.name.contains(a.name.as_str()) { Expr::True(a.pos) } else { Expr::False(a.pos) }
} }
// 'x' in "xxxxx" // 'x' in "xxxxx"
(Expr::CharConstant(a), Expr::StringConstant(b)) => { (Expr::CharConstant(a), Expr::StringConstant(b)) => {
state.set_dirty(); state.set_dirty();
if b.0.contains(a.0) { Expr::True(a.1) } else { Expr::False(a.1) } if b.name.contains(a.0) { Expr::True(a.1) } else { Expr::False(a.1) }
} }
// "xxx" in #{...} // "xxx" in #{...}
(Expr::StringConstant(a), Expr::Map(b)) => { (Expr::StringConstant(a), Expr::Map(b)) => {
state.set_dirty(); state.set_dirty();
if b.0.iter().find(|((name, _), _)| *name == a.0).is_some() { if b.0.iter().find(|(x, _)| x.name == a.name).is_some() {
Expr::True(a.1) Expr::True(a.pos)
} else { } else {
Expr::False(a.1) Expr::False(a.pos)
} }
} }
// 'x' in #{...} // 'x' in #{...}
@ -548,7 +544,7 @@ fn optimize_expr(expr: Expr, state: &mut State) -> Expr {
state.set_dirty(); state.set_dirty();
let ch = a.0.to_string(); let ch = a.0.to_string();
if b.0.iter().find(|((name, _), _)| name == &ch).is_some() { if b.0.iter().find(|(x, _)| x.name == &ch).is_some() {
Expr::True(a.1) Expr::True(a.1)
} else { } else {
Expr::False(a.1) Expr::False(a.1)
@ -697,24 +693,20 @@ fn optimize_expr(expr: Expr, state: &mut State) -> Expr {
} }
// constant-name // constant-name
Expr::Variable(x) if x.1.is_none() && state.contains_constant(&(x.0).0) => { Expr::Variable(x) if x.1.is_none() && state.contains_constant(&x.0.name) => {
let (name, pos) = x.0;
state.set_dirty(); state.set_dirty();
// Replace constant with value // Replace constant with value
let mut expr = state.find_constant(&name).unwrap().clone(); let mut expr = state.find_constant(&x.0.name).unwrap().clone();
expr.set_position(pos); expr.set_position(x.0.pos);
expr expr
} }
// Custom syntax // Custom syntax
#[cfg(feature = "internals")] Expr::Custom(x) => Expr::Custom(Box::new(CustomExpr {
Expr::Custom(x) => Expr::Custom(Box::new(( keywords: x.keywords.into_iter().map(|expr| optimize_expr(expr, state)).collect(),
CustomExpr( ..*x
(x.0).0.into_iter().map(|expr| optimize_expr(expr, state)).collect(), })),
(x.0).1),
x.1
))),
// All other expressions - skip // All other expressions - skip
expr => expr, expr => expr,
@ -776,7 +768,7 @@ fn optimize(
let expr = optimize_expr(expr, &mut state); let expr = optimize_expr(expr, &mut state);
if expr.is_literal() { if expr.is_literal() {
state.push_constant(&var_def.0, expr.clone()); state.push_constant(&var_def.name, expr.clone());
} }
// Keep it in the global scope // Keep it in the global scope
@ -788,7 +780,7 @@ fn optimize(
} }
} }
Stmt::Const(ref var_def, None, _) => { Stmt::Const(ref var_def, None, _) => {
state.push_constant(&var_def.0, Expr::Unit(var_def.1)); state.push_constant(&var_def.name, Expr::Unit(var_def.pos));
// Keep it in the global scope // Keep it in the global scope
stmt stmt

View File

@ -1,13 +1,13 @@
#![allow(non_snake_case)] #![allow(non_snake_case)]
use crate::def_package; use crate::def_package;
use crate::parser::INT;
use crate::plugin::*; use crate::plugin::*;
use crate::INT;
use crate::{result::EvalAltResult, token::Position}; use crate::{result::EvalAltResult, token::Position};
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
use crate::parser::FLOAT; use crate::FLOAT;
#[cfg(feature = "no_std")] #[cfg(feature = "no_std")]
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]

View File

@ -1,14 +1,15 @@
#![cfg(not(feature = "no_index"))] #![cfg(not(feature = "no_index"))]
#![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::engine::Array; use crate::engine::Array;
use crate::fn_native::{FnPtr, NativeCallContext}; use crate::fn_native::{FnPtr, NativeCallContext};
use crate::parser::{ImmutableString, INT};
use crate::plugin::*; use crate::plugin::*;
use crate::result::EvalAltResult; use crate::result::EvalAltResult;
use crate::token::Position; use crate::token::Position;
use crate::utils::ImmutableString;
use crate::INT;
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
use crate::engine::Map; use crate::engine::Map;
@ -40,12 +41,12 @@ macro_rules! gen_array_functions {
} }
#[rhai_fn(return_raw)] #[rhai_fn(return_raw)]
pub fn pad(context: NativeCallContext, list: &mut Array, len: INT, item: $arg_type) -> Result<Dynamic, Box<EvalAltResult>> { pub fn pad(_context: NativeCallContext, list: &mut Array, len: INT, item: $arg_type) -> Result<Dynamic, Box<EvalAltResult>> {
// Check if array will be over max size limit // Check if array will be over max size limit
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
if context.engine().max_array_size() > 0 && len > 0 && (len as usize) > context.engine().max_array_size() { if _context.engine().max_array_size() > 0 && len > 0 && (len as usize) > _context.engine().max_array_size() {
return EvalAltResult::ErrorDataTooLarge( return EvalAltResult::ErrorDataTooLarge(
"Size of array".to_string(), context.engine().max_array_size(), len as usize, Position::none(), "Size of array".to_string(), _context.engine().max_array_size(), len as usize, Position::none(),
).into(); ).into();
} }

View File

@ -1,8 +1,8 @@
use crate::any::Dynamic;
use crate::def_package; use crate::def_package;
use crate::parser::ImmutableString; use crate::dynamic::Dynamic;
use crate::plugin::*; use crate::plugin::*;
use crate::result::EvalAltResult; use crate::result::EvalAltResult;
use crate::utils::ImmutableString;
def_package!(crate:EvalPackage:"Disable 'eval'.", lib, { def_package!(crate:EvalPackage:"Disable 'eval'.", lib, {
combine_with_exported_module!(lib, "eval", eval_override); combine_with_exported_module!(lib, "eval", eval_override);

View File

@ -1,7 +1,7 @@
use crate::any::Variant;
use crate::def_package; use crate::def_package;
use crate::parser::INT; use crate::dynamic::Variant;
use crate::result::EvalAltResult; use crate::result::EvalAltResult;
use crate::INT;
use crate::stdlib::{ use crate::stdlib::{
boxed::Box, boxed::Box,

View File

@ -1,10 +1,11 @@
#![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::plugin::*; use crate::plugin::*;
use crate::utils::ImmutableString;
use crate::INT;
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
use crate::engine::Array; use crate::engine::Array;

View File

@ -1,12 +1,12 @@
#![allow(non_snake_case)] #![allow(non_snake_case)]
use crate::def_package; use crate::def_package;
use crate::parser::INT;
use crate::plugin::*; use crate::plugin::*;
use crate::token::Position; use crate::token::Position;
use crate::INT;
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
use crate::parser::FLOAT; use crate::FLOAT;
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
use crate::result::EvalAltResult; use crate::result::EvalAltResult;
@ -111,7 +111,7 @@ mod int_functions {
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
#[export_module] #[export_module]
mod trig_functions { mod trig_functions {
use crate::parser::FLOAT; use crate::FLOAT;
pub fn sin(x: FLOAT) -> FLOAT { pub fn sin(x: FLOAT) -> FLOAT {
x.to_radians().sin() x.to_radians().sin()
@ -154,7 +154,7 @@ mod trig_functions {
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
#[export_module] #[export_module]
mod float_functions { mod float_functions {
use crate::parser::FLOAT; use crate::FLOAT;
pub fn sqrt(x: FLOAT) -> FLOAT { pub fn sqrt(x: FLOAT) -> FLOAT {
x.sqrt() x.sqrt()

View File

@ -3,8 +3,9 @@
use crate::def_package; use crate::def_package;
use crate::engine::{FN_TO_STRING, KEYWORD_DEBUG, KEYWORD_PRINT}; use crate::engine::{FN_TO_STRING, KEYWORD_DEBUG, KEYWORD_PRINT};
use crate::fn_native::FnPtr; use crate::fn_native::FnPtr;
use crate::parser::{ImmutableString, INT};
use crate::plugin::*; use crate::plugin::*;
use crate::utils::ImmutableString;
use crate::INT;
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
use crate::engine::Array; use crate::engine::Array;

View File

@ -1,11 +1,12 @@
#![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::plugin::*; use crate::plugin::*;
use crate::utils::ImmutableString;
use crate::StaticVec; use crate::StaticVec;
use crate::INT;
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
use crate::{result::EvalAltResult, token::Position}; use crate::{result::EvalAltResult, token::Position};

View File

@ -2,14 +2,14 @@
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::parser::INT; use crate::dynamic::Dynamic;
use crate::plugin::*; use crate::plugin::*;
use crate::result::EvalAltResult; use crate::result::EvalAltResult;
use crate::INT;
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
use crate::parser::FLOAT; use crate::FLOAT;
use crate::stdlib::boxed::Box; use crate::stdlib::boxed::Box;

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +1,11 @@
//! Module defining macros for developing _plugins_. //! Module defining macros for developing _plugins_.
pub use crate::any::Dynamic; pub use crate::ast::FnAccess;
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};
pub use crate::module::Module; pub use crate::module::Module;
pub use crate::parser::FnAccess;
pub use crate::result::EvalAltResult; pub use crate::result::EvalAltResult;
pub use crate::utils::ImmutableString; pub use crate::utils::ImmutableString;

View File

@ -1,10 +1,10 @@
//! 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::token::Position; use crate::token::Position;
use crate::utils::ImmutableString; use crate::utils::ImmutableString;
use crate::INT;
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
use crate::engine::is_anonymous_fn; use crate::engine::is_anonymous_fn;

View File

@ -1,7 +1,8 @@
//! 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::ast::Expr;
use crate::parser::{map_dynamic_to_expr, Expr}; use crate::dynamic::{Dynamic, Variant};
use crate::parser::map_dynamic_to_expr;
use crate::token::Position; use crate::token::Position;
use crate::stdlib::{borrow::Cow, boxed::Box, iter, string::String, vec::Vec}; use crate::stdlib::{borrow::Cow, boxed::Box, iter, string::String, vec::Vec};

View File

@ -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;

View File

@ -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;

View File

@ -1,10 +1,10 @@
//! Module implementing custom syntax for `Engine`. //! Module implementing custom syntax for `Engine`.
use crate::any::Dynamic; use crate::ast::Expr;
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::parser::Expr; use crate::parse_error::{LexError, ParseError};
use crate::result::EvalAltResult; use crate::result::EvalAltResult;
use crate::token::{is_valid_identifier, Position, Token}; use crate::token::{is_valid_identifier, Position, Token};
use crate::utils::ImmutableString; use crate::utils::ImmutableString;

View File

@ -8,12 +8,12 @@ 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::StaticVec; use crate::StaticVec;
use crate::INT;
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
use crate::parser::FLOAT; use crate::FLOAT;
use crate::stdlib::{ use crate::stdlib::{
borrow::Cow, borrow::Cow,

View File

@ -1,14 +1,11 @@
//! A helper module containing unsafe utility functions. //! A helper module containing unsafe utility functions.
use crate::any::Variant; use crate::dynamic::Variant;
use crate::engine::State;
use crate::stdlib::{ use crate::stdlib::{
any::{Any, TypeId}, any::{Any, TypeId},
borrow::Cow,
boxed::Box, boxed::Box,
mem, ptr, mem, ptr,
string::ToString,
}; };
/// Cast a type into another type. /// Cast a type into another type.
@ -46,7 +43,7 @@ pub fn unsafe_cast_box<X: Variant, T: Variant>(item: Box<X>) -> Result<Box<T>, B
/// # DANGEROUS!!! /// # DANGEROUS!!!
/// ///
/// A dangerous function that blindly casts a `&str` from one lifetime to a `Cow<str>` of /// A dangerous function that blindly casts a `&str` from one lifetime to a `&str` of
/// another lifetime. This is mainly used to let us push a block-local variable into the /// another lifetime. This is mainly used to let us push a block-local variable into the
/// current `Scope` without cloning the variable name. Doing this is safe because all local /// current `Scope` without cloning the variable name. Doing this is safe because all local
/// variables in the `Scope` are cleared out before existing the block. /// variables in the `Scope` are cleared out before existing the block.
@ -54,15 +51,8 @@ pub fn unsafe_cast_box<X: Variant, T: Variant>(item: Box<X>) -> Result<Box<T>, B
/// Force-casting a local variable's lifetime to the current `Scope`'s larger lifetime saves /// Force-casting a local variable's lifetime to the current `Scope`'s larger lifetime saves
/// on allocations and string cloning, thus avoids us having to maintain a chain of `Scope`'s. /// on allocations and string cloning, thus avoids us having to maintain a chain of `Scope`'s.
#[inline] #[inline]
pub fn unsafe_cast_var_name_to_lifetime<'s>(name: &str, state: &State) -> Cow<'s, str> { pub fn unsafe_cast_var_name_to_lifetime<'s>(name: &str) -> &'s str {
// If not at global level, we can force-cast // WARNING - force-cast the variable name into the scope's lifetime to avoid cloning it
if state.scope_level > 0 { // this is safe because all local variables are cleared at the end of the block
// WARNING - force-cast the variable name into the scope's lifetime to avoid cloning it unsafe { mem::transmute(name) }
// this is safe because all local variables are cleared at the end of the block
unsafe { mem::transmute::<_, &'s str>(name) }.into()
} else {
// The variable is introduced at global (top) level and may persist after the script run.
// Therefore, clone the variable name.
name.to_string().into()
}
} }

View File

@ -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},
@ -42,14 +42,6 @@ impl Hasher for StraightHasher {
} }
} }
impl StraightHasher {
/// Create a `StraightHasher`.
#[inline(always)]
pub fn new() -> Self {
Self(0)
}
}
/// A hash builder for `StraightHasher`. /// A hash builder for `StraightHasher`.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Default)] #[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Default)]
pub struct StraightHasherBuilder; pub struct StraightHasherBuilder;
@ -59,7 +51,7 @@ impl BuildHasher for StraightHasherBuilder {
#[inline(always)] #[inline(always)]
fn build_hasher(&self) -> Self::Hasher { fn build_hasher(&self) -> Self::Hasher {
StraightHasher::new() Default::default()
} }
} }
@ -72,22 +64,61 @@ 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());
s.write_usize(num); if let Some(num) = num {
params.for_each(|t| t.hash(&mut s)); s.write_usize(num);
} else {
params.for_each(|t| t.hash(s));
}
s.finish() s.finish()
} }