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
==============
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
---------
@ -24,6 +26,11 @@ New features
* Low-level API for custom syntax allowing more flexibility in designing the syntax.
* `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
==============

View File

@ -4,7 +4,7 @@ error[E0277]: the trait bound `NonClonable: Clone` is not satisfied
11 | pub fn test_fn(input: f32) -> 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 {
| ----- 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 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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 {
| ----- 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.
use crate::fn_native::{FnPtr, SendSync};
use crate::parser::{ImmutableString, INT};
use crate::r#unsafe::{unsafe_cast_box, unsafe_try_cast};
use crate::utils::ImmutableString;
use crate::INT;
#[cfg(not(feature = "no_closure"))]
use crate::fn_native::{shared_try_take, Locked, Shared};
#[cfg(not(feature = "no_float"))]
use crate::parser::FLOAT;
use crate::FLOAT;
#[cfg(not(feature = "no_index"))]
use crate::engine::Array;

View File

@ -1,21 +1,21 @@
//! 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_native::{Callback, FnPtr, OnVarCallback};
use crate::module::{Module, ModuleRef};
use crate::optimize::OptimizationLevel;
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::result::EvalAltResult;
use crate::scope::{EntryType as ScopeEntryType, Scope};
use crate::syntax::CustomSyntax;
use crate::token::Position;
use crate::{calc_fn_hash, StaticVec};
use crate::{calc_native_fn_hash, StaticVec};
#[cfg(not(feature = "no_index"))]
use crate::parser::INT;
use crate::INT;
#[cfg(not(feature = "no_module"))]
use crate::module::ModuleResolver;
@ -29,10 +29,11 @@ use crate::utils::ImmutableString;
#[cfg(not(feature = "no_closure"))]
#[cfg(not(feature = "no_object"))]
use crate::any::DynamicWriteLock;
use crate::dynamic::DynamicWriteLock;
use crate::stdlib::{
any::type_name,
borrow::Cow,
boxed::Box,
collections::{HashMap, HashSet},
fmt, format,
@ -388,10 +389,10 @@ pub struct State {
}
impl State {
/// Create a new `State`.
/// Is the state currently at global (root) level?
#[inline(always)]
pub fn new() -> Self {
Default::default()
pub fn is_global(&self) -> bool {
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(not(feature = "no_module"))]
#[inline(always)]
pub fn imports(&self) -> &'a Imports {
pub fn imports(&'a self) -> &'a Imports {
self.mods
}
/// Get an iterator over the namespaces containing definition of all script-defined functions.
@ -764,7 +765,7 @@ impl Engine {
match expr {
Expr::Variable(v) => match v.as_ref() {
// Qualified variable
((name, pos), Some(modules), hash_var, _) => {
(Ident { name, pos }, Some(modules), hash_var, _) => {
let module = search_imports_mut(mods, state, modules)?;
let target = module.get_qualified_var_mut(*hash_var).map_err(|mut err| {
match *err {
@ -796,7 +797,7 @@ impl Engine {
this_ptr: &'s mut Option<&mut Dynamic>,
expr: &'a Expr,
) -> 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(),
_ => unreachable!(),
};
@ -1187,7 +1188,10 @@ impl Engine {
match dot_lhs {
// id.??? or id[???]
Expr::Variable(x) => {
let (var_name, var_pos) = &x.0;
let Ident {
name: var_name,
pos: var_pos,
} = &x.0;
self.inc_operations(state)
.map_err(|err| err.fill_position(*var_pos))?;
@ -1438,8 +1442,7 @@ impl Engine {
let args = &mut [&mut lhs_value.clone(), value];
// Qualifiers (none) + function name + number of arguments + argument `TypeId`'s.
let hash =
calc_fn_hash(empty(), op, args.len(), args.iter().map(|a| a.type_id()));
let hash = calc_native_fn_hash(empty(), op, args.iter().map(|a| a.type_id()));
if self
.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()),
#[cfg(not(feature = "no_float"))]
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::FnPointer(x) => Ok(FnPtr::new_unchecked(x.0.clone(), Default::default()).into()),
Expr::Variable(x) if (x.0).0 == KEYWORD_THIS => {
Expr::FnPointer(x) => {
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 {
Ok(val.clone())
} else {
EvalAltResult::ErrorUnboundThis((x.0).1).into()
EvalAltResult::ErrorUnboundThis((x.0).pos).into()
}
}
Expr::Variable(_) => {
@ -1533,9 +1538,9 @@ impl Engine {
#[cfg(not(feature = "no_object"))]
Expr::Map(x) => Ok(Dynamic(Union::Map(Box::new(
x.0.iter()
.map(|((key, _), expr)| {
.map(|(key, expr)| {
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<_, _>, _>>()?,
)))),
@ -1687,7 +1692,7 @@ impl Engine {
// Qualifiers (none) + function name + number of arguments + argument `TypeId`'s.
let arg_types =
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
.global_module
@ -1885,7 +1890,11 @@ impl Engine {
if let Some(func) = func {
// 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, ());
let index = scope.len() - 1;
state.scope_level += 1;
@ -1929,7 +1938,7 @@ impl Engine {
// Try/Catch statement
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
.eval_stmt(scope, mods, state, lib, this_ptr, try_body, level)
@ -1951,8 +1960,12 @@ impl Engine {
let orig_scope_len = scope.len();
state.scope_level += 1;
if let Some((var_name, _)) = var_def {
let var_name = unsafe_cast_var_name_to_lifetime(var_name, &state);
if let Some(Ident { name, .. }) = var_def {
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);
}
@ -2016,7 +2029,11 @@ impl Engine {
} else {
().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);
Ok(Default::default())
}
@ -2039,7 +2056,7 @@ impl Engine {
if let Some(name_def) = alias {
module.index_all_sub_modules();
mods.push((name_def.0.clone(), module));
mods.push((name_def.name.clone(), module));
}
state.modules += 1;
@ -2059,13 +2076,13 @@ impl Engine {
// Export statement
#[cfg(not(feature = "no_module"))]
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
if let Some(index) = scope.get_index(id).map(|(i, _)| i) {
let alias = rename.as_ref().map(|(n, _)| n).unwrap_or_else(|| id);
if let Some(index) = scope.get_index(name).map(|(i, _)| i) {
let alias = rename.as_ref().map(|x| &x.name).unwrap_or_else(|| name);
scope.set_entry_alias(index, alias.clone());
} else {
return EvalAltResult::ErrorVariableNotFound(id.into(), *id_pos).into();
return EvalAltResult::ErrorVariableNotFound(name.into(), *id_pos).into();
}
}
Ok(Default::default())
@ -2073,7 +2090,7 @@ impl Engine {
// Share statement
#[cfg(not(feature = "no_closure"))]
Stmt::Share(var_name, _) => {
Stmt::Share(Ident { name: var_name, .. }) => {
match scope.get_index(var_name) {
Some((index, ScopeEntryType::Normal)) => {
let (val, _) = scope.get_mut(index);

View File

@ -1,11 +1,11 @@
//! Module that defines the extern API of `Engine`.
use crate::any::{Dynamic, Variant};
use crate::engine::{Engine, EvalContext, Imports, State};
use crate::error::ParseError;
use crate::ast::AST;
use crate::dynamic::{Dynamic, Variant};
use crate::engine::{Engine, EvalContext, Imports};
use crate::fn_native::{FnCallArgs, NativeCallContext, SendSync};
use crate::optimize::OptimizationLevel;
use crate::parser::AST;
use crate::parse_error::ParseError;
use crate::result::EvalAltResult;
use crate::scope::Scope;
use crate::token::Position;
@ -19,7 +19,7 @@ use crate::{
#[cfg(not(feature = "no_object"))]
use crate::{
engine::{make_getter, make_setter, Map},
error::ParseErrorType,
parse_error::ParseErrorType,
token::Token,
};
@ -1619,7 +1619,7 @@ impl Engine {
.get_script_fn(name, args.len(), true)
.ok_or_else(|| EvalAltResult::ErrorFunctionNotFound(name.into(), Position::none()))?;
let mut state = State::new();
let mut state = Default::default();
let mut mods = Default::default();
// Check for data race.

View File

@ -2,7 +2,7 @@
#![allow(non_snake_case)]
use crate::any::{Dynamic, Variant};
use crate::dynamic::{Dynamic, Variant};
use crate::StaticVec;
/// Trait that represents arguments to a function call.

View File

@ -1,30 +1,31 @@
//! Implement function-calling mechanism for `Engine`.
use crate::any::Dynamic;
use crate::ast::{Expr, Stmt};
use crate::dynamic::Dynamic;
use crate::engine::{
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_PRINT, KEYWORD_TYPE_OF,
};
use crate::error::ParseErrorType;
use crate::fn_native::{FnCallArgs, FnPtr};
use crate::module::{Module, ModuleRef};
use crate::optimize::OptimizationLevel;
use crate::parser::{Expr, ImmutableString, Stmt, INT};
use crate::parse_error::ParseErrorType;
use crate::result::EvalAltResult;
use crate::scope::Scope;
use crate::stdlib::ops::Deref;
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"))]
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,
};
#[cfg(not(feature = "no_float"))]
use crate::parser::FLOAT;
use crate::FLOAT;
#[cfg(not(feature = "no_index"))]
use crate::engine::{FN_IDX_GET, FN_IDX_SET};
@ -50,6 +51,9 @@ use crate::stdlib::{
vec::Vec,
};
#[cfg(not(feature = "no_function"))]
use crate::stdlib::borrow::Cow;
#[cfg(feature = "no_std")]
#[cfg(not(feature = "no_float"))]
use num_traits::float::Float;
@ -376,7 +380,7 @@ impl Engine {
.iter()
.zip(args.iter_mut().map(|v| mem::take(*v)))
.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)
}),
);
@ -438,15 +442,8 @@ impl Engine {
pub_only: bool,
) -> bool {
let arg_types = arg_types.as_ref();
let arg_len = if arg_types.is_empty() {
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());
let hash_fn = calc_native_fn_hash(empty(), name, arg_types.iter().cloned());
let hash_script = calc_script_fn_hash(empty(), name, arg_types.len());
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.
let arg_types = args.iter().map(|a| a.type_id());
let hash_fn = calc_fn_hash(
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,
);
let hash_fn = calc_native_fn_hash(empty(), fn_name, arg_types);
match fn_name {
// type_of
@ -644,7 +631,7 @@ impl Engine {
statements: impl IntoIterator<Item = &'a Stmt>,
lib: &[&Module],
) -> Result<(Dynamic, u64), Box<EvalAltResult>> {
let mut state = State::new();
let mut state = Default::default();
statements
.into_iter()
@ -740,7 +727,7 @@ impl Engine {
let hash = if native {
0
} 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
let mut curry = fn_ptr.curry().iter().cloned().collect::<StaticVec<_>>();
@ -767,7 +754,7 @@ impl Engine {
let hash = if native {
0
} 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
let mut curry = fn_ptr.curry().iter().cloned().collect::<StaticVec<_>>();
@ -830,7 +817,7 @@ impl Engine {
hash = if native {
0
} 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()
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) {
// Fn - only in function call style
@ -962,12 +949,12 @@ impl Engine {
// Recalculate hash
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()
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) {
let var_name =
@ -981,10 +968,9 @@ impl Engine {
// Handle is_def_fn()
if name == KEYWORD_IS_DEF_FN && args_expr.len() == 2 {
let hash_fn = calc_fn_hash(
let hash_fn = calc_native_fn_hash(
empty(),
name,
2,
[TypeId::of::<ImmutableString>(), TypeId::of::<INT>()]
.iter()
.cloned(),
@ -1006,7 +992,7 @@ impl Engine {
return Ok(if num_params < 0 {
false
} 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))
}
.into());
@ -1015,7 +1001,7 @@ impl Engine {
// Handle eval()
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) {
// eval - only in function call style
@ -1184,8 +1170,9 @@ impl Engine {
// 1) Calculate a hash in a similar manner to script-defined functions,
// i.e. qualifiers + function name + number of arguments.
// 2) Calculate a second hash with no qualifiers, empty function name,
// zero number of arguments, and the actual list of argument `TypeId`'.s
let hash_fn_args = calc_fn_hash(empty(), "", 0, args.iter().map(|a| a.type_id()));
// and the actual list of argument `TypeId`'.s
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.
let hash_qualified_fn = hash_script ^ hash_fn_args;

View File

@ -3,10 +3,10 @@
#![cfg(not(feature = "no_function"))]
#![allow(non_snake_case)]
use crate::any::Variant;
use crate::ast::AST;
use crate::dynamic::Variant;
use crate::engine::Engine;
use crate::error::ParseError;
use crate::parser::AST;
use crate::parse_error::ParseError;
use crate::result::EvalAltResult;
use crate::scope::Scope;

View File

@ -1,14 +1,14 @@
//! 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::module::Module;
use crate::parser::{FnAccess, ScriptFnDef};
use crate::plugin::PluginFunction;
use crate::result::EvalAltResult;
use crate::token::{is_valid_identifier, Position};
use crate::utils::ImmutableString;
use crate::{calc_fn_hash, StaticVec};
use crate::{calc_script_fn_hash, StaticVec};
#[cfg(not(feature = "no_function"))]
use crate::engine::FN_ANONYMOUS;
@ -176,7 +176,7 @@ impl FnPtr {
let has_this = this_ptr.is_some();
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 {
args.insert(0, obj);

View File

@ -2,10 +2,10 @@
#![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::fn_native::{CallableFunction, FnAny, FnCallArgs, NativeCallContext, SendSync};
use crate::parser::FnAccess;
use crate::r#unsafe::unsafe_cast_box;
use crate::result::EvalAltResult;
use crate::utils::ImmutableString;

View File

@ -57,10 +57,11 @@
#[cfg(feature = "no_std")]
extern crate alloc;
mod any;
mod api;
mod ast;
mod dynamic;
mod engine;
mod error;
mod engine_api;
mod engine_settings;
mod fn_args;
mod fn_call;
mod fn_func;
@ -69,43 +70,60 @@ mod fn_register;
mod module;
mod optimize;
pub mod packages;
mod parse_error;
mod parser;
pub mod plugin;
mod result;
mod scope;
#[cfg(feature = "serde")]
mod serde_impl;
mod settings;
mod stdlib;
mod syntax;
mod token;
mod r#unsafe;
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 error::{ParseError, ParseErrorType};
pub use fn_native::{FnPtr, NativeCallContext};
pub use fn_register::{RegisterFn, RegisterResultFn};
pub use module::Module;
pub use parser::{ImmutableString, AST, INT};
pub use parse_error::{ParseError, ParseErrorType};
pub use result::EvalAltResult;
pub use scope::Scope;
pub use syntax::Expression;
pub use token::Position;
pub use utils::ImmutableString;
#[cfg(feature = "internals")]
pub use utils::calc_fn_hash;
pub use utils::{calc_native_fn_hash, calc_script_fn_hash};
#[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::*;
#[cfg(not(feature = "no_function"))]
pub use parser::FnAccess;
#[cfg(feature = "no_function")]
pub use parser::FnAccess;
pub use ast::FnAccess;
#[cfg(not(feature = "no_function"))]
pub use fn_func::Func;
@ -116,9 +134,6 @@ pub use engine::Array;
#[cfg(not(feature = "no_object"))]
pub use engine::Map;
#[cfg(not(feature = "no_float"))]
pub use parser::FLOAT;
#[cfg(not(feature = "no_module"))]
pub use module::ModuleResolver;
@ -141,7 +156,7 @@ pub use optimize::OptimizationLevel;
#[cfg(feature = "internals")]
#[deprecated(note = "this type is volatile and may change")]
pub use error::LexError;
pub use parse_error::LexError;
#[cfg(feature = "internals")]
#[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")]
#[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")]
#[deprecated(note = "this type is volatile and may change")]

View File

@ -1,21 +1,21 @@
//! 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_register::by_value as cast_arg;
use crate::parser::FnAccess;
use crate::result::EvalAltResult;
use crate::token::{Position, Token};
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"))]
use crate::{fn_native::Shared, parser::ScriptFnDef};
use crate::{ast::ScriptFnDef, fn_native::Shared};
#[cfg(not(feature = "no_module"))]
use crate::{
ast::AST,
engine::{Engine, Imports},
parser::AST,
scope::{Entry as ScopeEntry, Scope},
};
@ -268,7 +268,7 @@ impl Module {
/// Get a mutable reference to a modules-qualified variable.
/// 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)]
pub(crate) fn get_qualified_var_mut(
&mut self,
@ -291,7 +291,7 @@ impl Module {
pub(crate) fn set_script_fn(&mut self, fn_def: Shared<ScriptFnDef>) -> u64 {
// None + function name + number of arguments.
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(
hash_script,
(
@ -399,7 +399,7 @@ impl 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.
///
/// # Example
@ -441,31 +441,24 @@ impl Module {
) -> u64 {
let name = name.into();
let args_len = if arg_types.is_empty() {
// Distinguish between a script function and a function with no parameters
usize::MAX
} else {
arg_types.len()
};
let hash_fn = calc_native_fn_hash(empty(), &name, arg_types.iter().cloned());
let params = arg_types
.into_iter()
.cloned()
.map(|id| {
if id == TypeId::of::<&str>() {
TypeId::of::<ImmutableString>()
} else if id == TypeId::of::<String>() {
if id == TypeId::of::<&str>() || id == TypeId::of::<String>() {
TypeId::of::<ImmutableString>()
} else {
id
}
})
.collect();
.collect::<StaticVec<_>>();
let hash_fn = calc_fn_hash(empty(), &name, args_len, arg_types.iter().cloned());
self.functions
.insert(hash_fn, (name, access, args_len, Some(params), func.into()));
self.functions.insert(
hash_fn,
(name, access, params.len(), Some(params), func.into()),
);
self.indexed = false;
@ -1094,7 +1087,7 @@ impl Module {
/// 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.
#[inline(always)]
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.
/// 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`.
#[inline(always)]
pub(crate) fn get_qualified_fn(&self, hash_qualified_fn: u64) -> Option<&CallableFunction> {
@ -1408,7 +1401,7 @@ impl Module {
// Index all variables
module.variables.iter().for_each(|(var_name, value)| {
// 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()));
});
// Index all Rust functions
@ -1422,10 +1415,10 @@ impl Module {
// 1) Calculate a hash in a similar manner to script-defined functions,
// i.e. qualifiers + function name + number of arguments.
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,
// zero number of arguments, and the actual list of argument `TypeId`'.s
let hash_fn_args = calc_fn_hash(empty(), "", 0, params.iter().cloned());
// and the actual list of argument `TypeId`'.s
let hash_fn_args = calc_native_fn_hash(empty(), "", params.iter().cloned());
// 3) The final hash is the XOR of the two hashes.
let hash_qualified_fn = hash_qualified_script ^ hash_fn_args;
@ -1435,12 +1428,7 @@ impl Module {
_hash
} else {
// Qualifiers + function name + number of arguments.
calc_fn_hash(
qualifiers.iter().map(|&v| v),
&name,
*_num_params,
empty(),
)
calc_script_fn_hash(qualifiers.iter().map(|&v| v), &name, *_num_params)
};
functions.push((hash_qualified_script, func.clone()));
}

View File

@ -1,7 +1,7 @@
use crate::ast::AST;
use crate::engine::Engine;
use crate::fn_native::Locked;
use crate::module::{Module, ModuleResolver};
use crate::parser::AST;
use crate::result::EvalAltResult;
use crate::token::Position;

View File

@ -1,22 +1,20 @@
//! 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::{
Engine, KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_IS_DEF_FN, KEYWORD_IS_DEF_VAR, KEYWORD_PRINT,
KEYWORD_TYPE_OF,
};
use crate::fn_call::run_builtin_binary_op;
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::token::{is_valid_identifier, Position};
use crate::{calc_fn_hash, StaticVec};
use crate::{calc_native_fn_hash, StaticVec};
#[cfg(not(feature = "no_function"))]
use crate::parser::ReturnType;
#[cfg(feature = "internals")]
use crate::parser::CustomExpr;
use crate::ast::ReturnType;
use crate::stdlib::{
boxed::Box,
@ -137,12 +135,7 @@ fn call_fn_with_constant_arguments(
arg_values: &mut [Dynamic],
) -> Option<Dynamic> {
// Search built-in's and external functions
let hash_fn = calc_fn_hash(
empty(),
fn_name,
arg_values.len(),
arg_values.iter().map(|a| a.type_id()),
);
let hash_fn = calc_native_fn_hash(empty(), fn_name, arg_values.iter().map(|a| a.type_id()));
state
.engine
@ -283,18 +276,18 @@ fn optimize_stmt(stmt: Stmt, state: &mut State, preserve_result: bool) -> Stmt {
.into_iter()
.map(|stmt| match stmt {
// 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.push_constant(&name.0, expr);
state.push_constant(&var_def.name, expr);
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);
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.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
}
// Optimize the statement
@ -389,22 +382,25 @@ fn optimize_stmt(stmt: Stmt, state: &mut State, preserve_result: bool) -> Stmt {
}
}
// 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
state.set_dirty();
let pos = (x.0).0.position();
let mut statements: Vec<_> = Default::default();
statements.push(optimize_stmt((x.0).0, state, preserve_result));
let pos = x.0.position();
let mut statements = match optimize_stmt(x.0, state, preserve_result) {
Stmt::Block(statements, _) => statements,
stmt => vec![stmt],
};
statements.push(Stmt::Noop(pos));
Stmt::Block(statements, pos)
}
// try { block } catch ( var ) { block }
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((
(optimize_stmt(try_block, state, false), try_pos),
optimize_stmt(try_block, state, false),
var_name,
(optimize_stmt(catch_block, state, false), catch_pos),
optimize_stmt(catch_block, state, false),
pos,
)))
}
// expr;
@ -463,7 +459,7 @@ fn optimize_expr(expr: Expr, state: &mut State) -> Expr {
// All other items can be thrown away.
state.set_dirty();
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 })
.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.
state.set_dirty();
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 })
.unwrap_or_else(|| Expr::Unit(pos))
}
// 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
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) => Expr::Index(Box::new(BinaryExpr {
@ -520,27 +516,27 @@ fn optimize_expr(expr: Expr, state: &mut State) -> Expr {
// [ items .. ]
#[cfg(not(feature = "no_object"))]
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))),
// lhs in rhs
Expr::In(x) => match (x.lhs, x.rhs) {
// "xxx" in "xxxxx"
(Expr::StringConstant(a), Expr::StringConstant(b)) => {
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"
(Expr::CharConstant(a), Expr::StringConstant(b)) => {
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 #{...}
(Expr::StringConstant(a), Expr::Map(b)) => {
state.set_dirty();
if b.0.iter().find(|((name, _), _)| *name == a.0).is_some() {
Expr::True(a.1)
if b.0.iter().find(|(x, _)| x.name == a.name).is_some() {
Expr::True(a.pos)
} else {
Expr::False(a.1)
Expr::False(a.pos)
}
}
// 'x' in #{...}
@ -548,7 +544,7 @@ fn optimize_expr(expr: Expr, state: &mut State) -> Expr {
state.set_dirty();
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)
} else {
Expr::False(a.1)
@ -697,24 +693,20 @@ fn optimize_expr(expr: Expr, state: &mut State) -> Expr {
}
// constant-name
Expr::Variable(x) if x.1.is_none() && state.contains_constant(&(x.0).0) => {
let (name, pos) = x.0;
Expr::Variable(x) if x.1.is_none() && state.contains_constant(&x.0.name) => {
state.set_dirty();
// Replace constant with value
let mut expr = state.find_constant(&name).unwrap().clone();
expr.set_position(pos);
let mut expr = state.find_constant(&x.0.name).unwrap().clone();
expr.set_position(x.0.pos);
expr
}
// Custom syntax
#[cfg(feature = "internals")]
Expr::Custom(x) => Expr::Custom(Box::new((
CustomExpr(
(x.0).0.into_iter().map(|expr| optimize_expr(expr, state)).collect(),
(x.0).1),
x.1
))),
Expr::Custom(x) => Expr::Custom(Box::new(CustomExpr {
keywords: x.keywords.into_iter().map(|expr| optimize_expr(expr, state)).collect(),
..*x
})),
// All other expressions - skip
expr => expr,
@ -776,7 +768,7 @@ fn optimize(
let expr = optimize_expr(expr, &mut state);
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
@ -788,7 +780,7 @@ fn optimize(
}
}
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
stmt

View File

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

View File

@ -1,14 +1,15 @@
#![cfg(not(feature = "no_index"))]
#![allow(non_snake_case)]
use crate::any::Dynamic;
use crate::def_package;
use crate::dynamic::Dynamic;
use crate::engine::Array;
use crate::fn_native::{FnPtr, NativeCallContext};
use crate::parser::{ImmutableString, INT};
use crate::plugin::*;
use crate::result::EvalAltResult;
use crate::token::Position;
use crate::utils::ImmutableString;
use crate::INT;
#[cfg(not(feature = "no_object"))]
use crate::engine::Map;
@ -40,12 +41,12 @@ macro_rules! gen_array_functions {
}
#[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
#[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(
"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();
}

View File

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

View File

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

View File

@ -1,10 +1,11 @@
#![cfg(not(feature = "no_object"))]
use crate::any::Dynamic;
use crate::def_package;
use crate::dynamic::Dynamic;
use crate::engine::Map;
use crate::parser::{ImmutableString, INT};
use crate::plugin::*;
use crate::utils::ImmutableString;
use crate::INT;
#[cfg(not(feature = "no_index"))]
use crate::engine::Array;

View File

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

View File

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

View File

@ -1,11 +1,12 @@
#![allow(non_snake_case)]
use crate::any::Dynamic;
use crate::def_package;
use crate::dynamic::Dynamic;
use crate::fn_native::FnPtr;
use crate::parser::{ImmutableString, INT};
use crate::plugin::*;
use crate::utils::ImmutableString;
use crate::StaticVec;
use crate::INT;
#[cfg(not(feature = "unchecked"))]
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 crate::any::Dynamic;
use crate::def_package;
use crate::parser::INT;
use crate::dynamic::Dynamic;
use crate::plugin::*;
use crate::result::EvalAltResult;
use crate::INT;
#[cfg(not(feature = "no_float"))]
use crate::parser::FLOAT;
use crate::FLOAT;
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_.
pub use crate::any::Dynamic;
pub use crate::ast::FnAccess;
pub use crate::dynamic::Dynamic;
pub use crate::engine::Engine;
pub use crate::fn_native::{CallableFunction, FnCallArgs, NativeCallContext};
pub use crate::fn_register::{RegisterFn, RegisterResultFn};
pub use crate::module::Module;
pub use crate::parser::FnAccess;
pub use crate::result::EvalAltResult;
pub use crate::utils::ImmutableString;

View File

@ -1,10 +1,10 @@
//! Module containing error definitions for the evaluation process.
use crate::any::Dynamic;
use crate::error::ParseErrorType;
use crate::parser::INT;
use crate::dynamic::Dynamic;
use crate::parse_error::ParseErrorType;
use crate::token::Position;
use crate::utils::ImmutableString;
use crate::INT;
#[cfg(not(feature = "no_function"))]
use crate::engine::is_anonymous_fn;

View File

@ -1,7 +1,8 @@
//! Module that defines the `Scope` type representing a function call-stack scope.
use crate::any::{Dynamic, Variant};
use crate::parser::{map_dynamic_to_expr, Expr};
use crate::ast::Expr;
use crate::dynamic::{Dynamic, Variant};
use crate::parser::map_dynamic_to_expr;
use crate::token::Position;
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).
use super::str::ImmutableStringDeserializer;
use crate::any::{Dynamic, Union};
use crate::error::ParseErrorType;
use crate::dynamic::{Dynamic, Union};
use crate::parse_error::ParseErrorType;
use crate::result::EvalAltResult;
use crate::token::Position;
use crate::utils::ImmutableString;

View File

@ -1,6 +1,6 @@
//! 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::token::Position;

View File

@ -1,10 +1,10 @@
//! 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::error::{LexError, ParseError};
use crate::fn_native::{SendSync, Shared};
use crate::parser::Expr;
use crate::parse_error::{LexError, ParseError};
use crate::result::EvalAltResult;
use crate::token::{is_valid_identifier, Position, Token};
use crate::utils::ImmutableString;

View File

@ -8,12 +8,12 @@ use crate::engine::{
#[cfg(not(feature = "no_closure"))]
use crate::engine::KEYWORD_IS_SHARED;
use crate::error::LexError;
use crate::parser::INT;
use crate::parse_error::LexError;
use crate::StaticVec;
use crate::INT;
#[cfg(not(feature = "no_float"))]
use crate::parser::FLOAT;
use crate::FLOAT;
use crate::stdlib::{
borrow::Cow,

View File

@ -1,14 +1,11 @@
//! A helper module containing unsafe utility functions.
use crate::any::Variant;
use crate::engine::State;
use crate::dynamic::Variant;
use crate::stdlib::{
any::{Any, TypeId},
borrow::Cow,
boxed::Box,
mem, ptr,
string::ToString,
};
/// 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!!!
///
/// 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
/// 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.
@ -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
/// on allocations and string cloning, thus avoids us having to maintain a chain of `Scope`'s.
#[inline]
pub fn unsafe_cast_var_name_to_lifetime<'s>(name: &str, state: &State) -> Cow<'s, str> {
// If not at global level, we can force-cast
if state.scope_level > 0 {
// WARNING - force-cast the variable name into the scope's lifetime to avoid cloning it
// 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()
}
pub fn unsafe_cast_var_name_to_lifetime<'s>(name: &str) -> &'s str {
// WARNING - force-cast the variable name into the scope's lifetime to avoid cloning it
// this is safe because all local variables are cleared at the end of the block
unsafe { mem::transmute(name) }
}

View File

@ -9,7 +9,7 @@ use crate::stdlib::{
cmp::Ordering,
fmt,
hash::{BuildHasher, Hash, Hasher},
iter::FromIterator,
iter::{empty, FromIterator},
ops::{Add, AddAssign, Deref},
str::FromStr,
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`.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Default)]
pub struct StraightHasherBuilder;
@ -59,7 +51,7 @@ impl BuildHasher for StraightHasherBuilder {
#[inline(always)]
fn build_hasher(&self) -> Self::Hasher {
StraightHasher::new()
Default::default()
}
}
@ -72,22 +64,61 @@ impl BuildHasher for StraightHasherBuilder {
/// # Note
///
/// 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>,
fn_name: &str,
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>,
) -> u64 {
#[cfg(feature = "no_std")]
let mut s: AHasher = Default::default();
let s: &mut AHasher = &mut Default::default();
#[cfg(not(feature = "no_std"))]
let mut s = DefaultHasher::new();
let s = &mut DefaultHasher::new();
// 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_usize(num);
params.for_each(|t| t.hash(&mut s));
if let Some(num) = num {
s.write_usize(num);
} else {
params.for_each(|t| t.hash(s));
}
s.finish()
}