commit
45effc6276
@ -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
|
||||||
==============
|
==============
|
||||||
|
@ -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`
|
||||||
|
@ -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
1226
src/ast.rs
Normal file
File diff suppressed because it is too large
Load Diff
@ -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;
|
@ -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);
|
||||||
|
@ -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.
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
use crate::any::{Dynamic, Variant};
|
use crate::dynamic::{Dynamic, Variant};
|
||||||
use crate::StaticVec;
|
use crate::StaticVec;
|
||||||
|
|
||||||
/// Trait that represents arguments to a function call.
|
/// Trait that represents arguments to a function call.
|
||||||
|
@ -1,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;
|
||||||
|
|
||||||
|
@ -3,10 +3,10 @@
|
|||||||
#![cfg(not(feature = "no_function"))]
|
#![cfg(not(feature = "no_function"))]
|
||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
use crate::any::Variant;
|
use crate::ast::AST;
|
||||||
|
use crate::dynamic::Variant;
|
||||||
use crate::engine::Engine;
|
use crate::engine::Engine;
|
||||||
use crate::error::ParseError;
|
use crate::parse_error::ParseError;
|
||||||
use crate::parser::AST;
|
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::scope::Scope;
|
use crate::scope::Scope;
|
||||||
|
|
||||||
|
@ -1,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);
|
||||||
|
@ -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;
|
||||||
|
51
src/lib.rs
51
src/lib.rs
@ -57,10 +57,11 @@
|
|||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
mod any;
|
mod ast;
|
||||||
mod api;
|
mod dynamic;
|
||||||
mod engine;
|
mod engine;
|
||||||
mod error;
|
mod engine_api;
|
||||||
|
mod engine_settings;
|
||||||
mod fn_args;
|
mod fn_args;
|
||||||
mod fn_call;
|
mod fn_call;
|
||||||
mod fn_func;
|
mod fn_func;
|
||||||
@ -69,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")]
|
||||||
|
@ -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()));
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
|
use crate::ast::AST;
|
||||||
use crate::engine::Engine;
|
use crate::engine::Engine;
|
||||||
use crate::fn_native::Locked;
|
use crate::fn_native::Locked;
|
||||||
use crate::module::{Module, ModuleResolver};
|
use crate::module::{Module, ModuleResolver};
|
||||||
use crate::parser::AST;
|
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::token::Position;
|
use crate::token::Position;
|
||||||
|
|
||||||
|
@ -1,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
|
||||||
|
@ -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"))]
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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,
|
||||||
|
@ -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;
|
||||||
|
@ -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()
|
||||||
|
@ -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;
|
||||||
|
@ -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};
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
1376
src/parser.rs
1376
src/parser.rs
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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};
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
//! Implement deserialization support of `Dynamic` for [`serde`](https://crates.io/crates/serde).
|
//! Implement deserialization support of `Dynamic` for [`serde`](https://crates.io/crates/serde).
|
||||||
|
|
||||||
use super::str::ImmutableStringDeserializer;
|
use super::str::ImmutableStringDeserializer;
|
||||||
use crate::any::{Dynamic, Union};
|
use crate::dynamic::{Dynamic, Union};
|
||||||
use crate::error::ParseErrorType;
|
use crate::parse_error::ParseErrorType;
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::token::Position;
|
use crate::token::Position;
|
||||||
use crate::utils::ImmutableString;
|
use crate::utils::ImmutableString;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//! Implement serialization support of `Dynamic` for [`serde`](https://crates.io/crates/serde).
|
//! Implement serialization support of `Dynamic` for [`serde`](https://crates.io/crates/serde).
|
||||||
|
|
||||||
use crate::any::Dynamic;
|
use crate::dynamic::Dynamic;
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::token::Position;
|
use crate::token::Position;
|
||||||
|
|
||||||
|
@ -1,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;
|
||||||
|
@ -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,
|
||||||
|
@ -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()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
63
src/utils.rs
63
src/utils.rs
@ -9,7 +9,7 @@ use crate::stdlib::{
|
|||||||
cmp::Ordering,
|
cmp::Ordering,
|
||||||
fmt,
|
fmt,
|
||||||
hash::{BuildHasher, Hash, Hasher},
|
hash::{BuildHasher, Hash, Hasher},
|
||||||
iter::FromIterator,
|
iter::{empty, FromIterator},
|
||||||
ops::{Add, AddAssign, Deref},
|
ops::{Add, AddAssign, Deref},
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
string::{String, ToString},
|
string::{String, ToString},
|
||||||
@ -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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user