Code style and docs.
This commit is contained in:
parent
699131be58
commit
6667a22c0c
49
src/ast.rs
49
src/ast.rs
@ -1301,18 +1301,41 @@ pub struct OpAssignment {
|
|||||||
/// _(INTERNALS)_ An set of function call hashes.
|
/// _(INTERNALS)_ An set of function call hashes.
|
||||||
/// Exported under the `internals` feature only.
|
/// Exported under the `internals` feature only.
|
||||||
///
|
///
|
||||||
|
/// Two separate hashes are pre-calculated because of the following pattern:
|
||||||
|
///
|
||||||
|
/// ```rust,no_run
|
||||||
|
/// func(a, b, c); // Native: func(a, b, c) - 3 parameters
|
||||||
|
/// // Script: func(a, b, c) - 3 parameters
|
||||||
|
///
|
||||||
|
/// a.func(b, c); // Native: func(&mut a, b, c) - 3 parameters
|
||||||
|
/// // Script: func(b, c) - 2 parameters
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// For normal function calls, the native hash equals the script hash.
|
||||||
|
/// For method-style calls, the script hash contains one fewer parameter.
|
||||||
|
///
|
||||||
|
/// Function call hashes are used in the following manner:
|
||||||
|
///
|
||||||
|
/// * First, the script hash is tried, which contains only the called function's name plus the
|
||||||
|
/// of parameters.
|
||||||
|
///
|
||||||
|
/// * Next, the actual types of arguments are hashed and _combined_ with the native hash, which is
|
||||||
|
/// then used to search for a native function.
|
||||||
|
/// In other words, a native function call hash always contains the called function's name plus
|
||||||
|
/// the types of the arguments. This is to due to possible function overloading for different parameter types.
|
||||||
|
///
|
||||||
/// # Volatile Data Structure
|
/// # Volatile Data Structure
|
||||||
///
|
///
|
||||||
/// This type is volatile and may change.
|
/// This type is volatile and may change.
|
||||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Default)]
|
#[derive(Clone, Copy, Eq, PartialEq, Hash, Default)]
|
||||||
pub struct FnHash {
|
pub struct FnCallHash {
|
||||||
/// Pre-calculated hash for a script-defined function ([`None`] if native functions only).
|
/// Pre-calculated hash for a script-defined function ([`None`] if native functions only).
|
||||||
script: Option<u64>,
|
pub script: Option<u64>,
|
||||||
/// Pre-calculated hash for a native Rust function with no parameter types.
|
/// Pre-calculated hash for a native Rust function with no parameter types.
|
||||||
native: u64,
|
pub native: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for FnHash {
|
impl fmt::Debug for FnCallHash {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
if let Some(script) = self.script {
|
if let Some(script) = self.script {
|
||||||
if script == self.native {
|
if script == self.native {
|
||||||
@ -1326,8 +1349,8 @@ impl fmt::Debug for FnHash {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FnHash {
|
impl FnCallHash {
|
||||||
/// Create a [`FnHash`] with only the native Rust hash.
|
/// Create a [`FnCallHash`] with only the native Rust hash.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn from_native(hash: u64) -> Self {
|
pub fn from_native(hash: u64) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -1335,7 +1358,7 @@ impl FnHash {
|
|||||||
native: hash,
|
native: hash,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Create a [`FnHash`] with both native Rust and script function hashes set to the same value.
|
/// Create a [`FnCallHash`] with both native Rust and script function hashes set to the same value.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn from_script(hash: u64) -> Self {
|
pub fn from_script(hash: u64) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -1343,7 +1366,7 @@ impl FnHash {
|
|||||||
native: hash,
|
native: hash,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Create a [`FnHash`] with both native Rust and script function hashes.
|
/// Create a [`FnCallHash`] with both native Rust and script function hashes.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn from_script_and_native(script: u64, native: u64) -> Self {
|
pub fn from_script_and_native(script: u64, native: u64) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -1351,21 +1374,21 @@ impl FnHash {
|
|||||||
native,
|
native,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Is this [`FnHash`] native Rust only?
|
/// Is this [`FnCallHash`] native Rust only?
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn is_native_only(&self) -> bool {
|
pub fn is_native_only(&self) -> bool {
|
||||||
self.script.is_none()
|
self.script.is_none()
|
||||||
}
|
}
|
||||||
/// Get the script function hash from this [`FnHash`].
|
/// Get the script function hash from this [`FnCallHash`].
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// Panics if the [`FnHash`] is native Rust only.
|
/// Panics if the [`FnCallHash`] is native Rust only.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn script_hash(&self) -> u64 {
|
pub fn script_hash(&self) -> u64 {
|
||||||
self.script.unwrap()
|
self.script.unwrap()
|
||||||
}
|
}
|
||||||
/// Get the naive Rust function hash from this [`FnHash`].
|
/// Get the naive Rust function hash from this [`FnCallHash`].
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn native_hash(&self) -> u64 {
|
pub fn native_hash(&self) -> u64 {
|
||||||
self.native
|
self.native
|
||||||
@ -1381,7 +1404,7 @@ impl FnHash {
|
|||||||
#[derive(Debug, Clone, Default, Hash)]
|
#[derive(Debug, Clone, Default, Hash)]
|
||||||
pub struct FnCallExpr {
|
pub struct FnCallExpr {
|
||||||
/// Pre-calculated hash.
|
/// Pre-calculated hash.
|
||||||
pub hash: FnHash,
|
pub hash: FnCallHash,
|
||||||
/// Does this function call capture the parent scope?
|
/// Does this function call capture the parent scope?
|
||||||
pub capture: bool,
|
pub capture: bool,
|
||||||
/// List of function call arguments.
|
/// List of function call arguments.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//! Main module defining the script evaluation [`Engine`].
|
//! Main module defining the script evaluation [`Engine`].
|
||||||
|
|
||||||
use crate::ast::{Expr, FnCallExpr, FnHash, Ident, OpAssignment, ReturnType, Stmt, StmtBlock};
|
use crate::ast::{Expr, FnCallExpr, FnCallHash, Ident, OpAssignment, ReturnType, Stmt, StmtBlock};
|
||||||
use crate::dynamic::{map_std_type_name, AccessMode, Union, Variant};
|
use crate::dynamic::{map_std_type_name, AccessMode, Union, Variant};
|
||||||
use crate::fn_native::{
|
use crate::fn_native::{
|
||||||
CallableFunction, IteratorFn, OnDebugCallback, OnPrintCallback, OnProgressCallback,
|
CallableFunction, IteratorFn, OnDebugCallback, OnPrintCallback, OnProgressCallback,
|
||||||
@ -527,10 +527,8 @@ pub struct State {
|
|||||||
/// Embedded module resolver.
|
/// Embedded module resolver.
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
pub resolver: Option<Shared<crate::module::resolvers::StaticModuleResolver>>,
|
pub resolver: Option<Shared<crate::module::resolvers::StaticModuleResolver>>,
|
||||||
/// function resolution cache.
|
/// Function resolution cache and free list.
|
||||||
fn_resolution_caches: StaticVec<FnResolutionCache>,
|
fn_resolution_caches: (StaticVec<FnResolutionCache>, Vec<FnResolutionCache>),
|
||||||
/// Free resolution caches.
|
|
||||||
fn_resolution_caches_free_list: Vec<FnResolutionCache>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
@ -541,20 +539,19 @@ impl State {
|
|||||||
}
|
}
|
||||||
/// Get a mutable reference to the current function resolution cache.
|
/// Get a mutable reference to the current function resolution cache.
|
||||||
pub fn fn_resolution_cache_mut(&mut self) -> &mut FnResolutionCache {
|
pub fn fn_resolution_cache_mut(&mut self) -> &mut FnResolutionCache {
|
||||||
if self.fn_resolution_caches.is_empty() {
|
if self.fn_resolution_caches.0.is_empty() {
|
||||||
self.fn_resolution_caches
|
self.fn_resolution_caches
|
||||||
.push(HashMap::with_capacity_and_hasher(16, StraightHasherBuilder));
|
.0
|
||||||
|
.push(HashMap::with_capacity_and_hasher(64, StraightHasherBuilder));
|
||||||
}
|
}
|
||||||
self.fn_resolution_caches.last_mut().unwrap()
|
self.fn_resolution_caches.0.last_mut().unwrap()
|
||||||
}
|
}
|
||||||
/// Push an empty function resolution cache onto the stack and make it current.
|
/// Push an empty function resolution cache onto the stack and make it current.
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn push_fn_resolution_cache(&mut self) {
|
pub fn push_fn_resolution_cache(&mut self) {
|
||||||
self.fn_resolution_caches.push(
|
self.fn_resolution_caches
|
||||||
self.fn_resolution_caches_free_list
|
.0
|
||||||
.pop()
|
.push(self.fn_resolution_caches.1.pop().unwrap_or_default());
|
||||||
.unwrap_or_default(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
/// Remove the current function resolution cache from the stack and make the last one current.
|
/// Remove the current function resolution cache from the stack and make the last one current.
|
||||||
///
|
///
|
||||||
@ -562,9 +559,9 @@ impl State {
|
|||||||
///
|
///
|
||||||
/// Panics if there are no more function resolution cache in the stack.
|
/// Panics if there are no more function resolution cache in the stack.
|
||||||
pub fn pop_fn_resolution_cache(&mut self) {
|
pub fn pop_fn_resolution_cache(&mut self) {
|
||||||
let mut cache = self.fn_resolution_caches.pop().unwrap();
|
let mut cache = self.fn_resolution_caches.0.pop().unwrap();
|
||||||
cache.clear();
|
cache.clear();
|
||||||
self.fn_resolution_caches_free_list.push(cache);
|
self.fn_resolution_caches.1.push(cache);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1143,7 +1140,7 @@ impl Engine {
|
|||||||
let ((_, val_pos), _) = new_val;
|
let ((_, val_pos), _) = new_val;
|
||||||
|
|
||||||
let hash_set =
|
let hash_set =
|
||||||
FnHash::from_native(calc_fn_hash(empty(), FN_IDX_SET, 3));
|
FnCallHash::from_native(calc_fn_hash(empty(), FN_IDX_SET, 3));
|
||||||
let args = &mut [target_val, &mut idx_val2, &mut (new_val.0).0];
|
let args = &mut [target_val, &mut idx_val2, &mut (new_val.0).0];
|
||||||
|
|
||||||
self.exec_fn_call(
|
self.exec_fn_call(
|
||||||
@ -1221,7 +1218,7 @@ impl Engine {
|
|||||||
// xxx.id = ???
|
// xxx.id = ???
|
||||||
Expr::Property(x) if new_val.is_some() => {
|
Expr::Property(x) if new_val.is_some() => {
|
||||||
let (_, (setter, hash_set), Ident { pos, .. }) = x.as_ref();
|
let (_, (setter, hash_set), Ident { pos, .. }) = x.as_ref();
|
||||||
let hash = FnHash::from_native(*hash_set);
|
let hash = FnCallHash::from_native(*hash_set);
|
||||||
let mut new_val = new_val;
|
let mut new_val = new_val;
|
||||||
let mut args = [target_val, &mut (new_val.as_mut().unwrap().0).0];
|
let mut args = [target_val, &mut (new_val.as_mut().unwrap().0).0];
|
||||||
self.exec_fn_call(
|
self.exec_fn_call(
|
||||||
@ -1233,7 +1230,7 @@ impl Engine {
|
|||||||
// xxx.id
|
// xxx.id
|
||||||
Expr::Property(x) => {
|
Expr::Property(x) => {
|
||||||
let ((getter, hash_get), _, Ident { pos, .. }) = x.as_ref();
|
let ((getter, hash_get), _, Ident { pos, .. }) = x.as_ref();
|
||||||
let hash = FnHash::from_native(*hash_get);
|
let hash = FnCallHash::from_native(*hash_get);
|
||||||
let mut args = [target_val];
|
let mut args = [target_val];
|
||||||
self.exec_fn_call(
|
self.exec_fn_call(
|
||||||
mods, state, lib, getter, hash, &mut args, is_ref, true, *pos, None,
|
mods, state, lib, getter, hash, &mut args, is_ref, true, *pos, None,
|
||||||
@ -1282,8 +1279,8 @@ impl Engine {
|
|||||||
Expr::Property(p) => {
|
Expr::Property(p) => {
|
||||||
let ((getter, hash_get), (setter, hash_set), Ident { pos, .. }) =
|
let ((getter, hash_get), (setter, hash_set), Ident { pos, .. }) =
|
||||||
p.as_ref();
|
p.as_ref();
|
||||||
let hash_get = FnHash::from_native(*hash_get);
|
let hash_get = FnCallHash::from_native(*hash_get);
|
||||||
let hash_set = FnHash::from_native(*hash_set);
|
let hash_set = FnCallHash::from_native(*hash_set);
|
||||||
let arg_values = &mut [target_val, &mut Default::default()];
|
let arg_values = &mut [target_val, &mut Default::default()];
|
||||||
let args = &mut arg_values[..1];
|
let args = &mut arg_values[..1];
|
||||||
let (mut val, updated) = self.exec_fn_call(
|
let (mut val, updated) = self.exec_fn_call(
|
||||||
@ -1615,7 +1612,7 @@ impl Engine {
|
|||||||
let type_name = target.type_name();
|
let type_name = target.type_name();
|
||||||
let mut idx = idx;
|
let mut idx = idx;
|
||||||
let args = &mut [target, &mut idx];
|
let args = &mut [target, &mut idx];
|
||||||
let hash_get = FnHash::from_native(calc_fn_hash(empty(), FN_IDX_GET, 2));
|
let hash_get = FnCallHash::from_native(calc_fn_hash(empty(), FN_IDX_GET, 2));
|
||||||
self.exec_fn_call(
|
self.exec_fn_call(
|
||||||
_mods, state, _lib, FN_IDX_GET, hash_get, args, _is_ref, true, idx_pos, None,
|
_mods, state, _lib, FN_IDX_GET, hash_get, args, _is_ref, true, idx_pos, None,
|
||||||
_level,
|
_level,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//! Implement function-calling mechanism for [`Engine`].
|
//! Implement function-calling mechanism for [`Engine`].
|
||||||
|
|
||||||
use crate::ast::FnHash;
|
use crate::ast::FnCallHash;
|
||||||
use crate::engine::{
|
use crate::engine::{
|
||||||
FnResolutionCacheEntry, Imports, State, KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR,
|
FnResolutionCacheEntry, Imports, State, KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR,
|
||||||
KEYWORD_FN_PTR_CALL, KEYWORD_FN_PTR_CURRY, KEYWORD_IS_DEF_VAR, KEYWORD_PRINT, KEYWORD_TYPE_OF,
|
KEYWORD_FN_PTR_CALL, KEYWORD_FN_PTR_CURRY, KEYWORD_IS_DEF_VAR, KEYWORD_PRINT, KEYWORD_TYPE_OF,
|
||||||
@ -627,7 +627,7 @@ impl Engine {
|
|||||||
state: &mut State,
|
state: &mut State,
|
||||||
lib: &[&Module],
|
lib: &[&Module],
|
||||||
fn_name: &str,
|
fn_name: &str,
|
||||||
hash: FnHash,
|
hash: FnCallHash,
|
||||||
args: &mut FnCallArgs,
|
args: &mut FnCallArgs,
|
||||||
is_ref: bool,
|
is_ref: bool,
|
||||||
_is_method: bool,
|
_is_method: bool,
|
||||||
@ -893,7 +893,7 @@ impl Engine {
|
|||||||
state: &mut State,
|
state: &mut State,
|
||||||
lib: &[&Module],
|
lib: &[&Module],
|
||||||
fn_name: &str,
|
fn_name: &str,
|
||||||
mut hash: FnHash,
|
mut hash: FnCallHash,
|
||||||
target: &mut crate::engine::Target,
|
target: &mut crate::engine::Target,
|
||||||
(call_args, call_arg_positions): &mut (StaticVec<Dynamic>, StaticVec<Position>),
|
(call_args, call_arg_positions): &mut (StaticVec<Dynamic>, StaticVec<Position>),
|
||||||
pos: Position,
|
pos: Position,
|
||||||
@ -913,7 +913,7 @@ impl Engine {
|
|||||||
let fn_name = fn_ptr.fn_name();
|
let fn_name = fn_ptr.fn_name();
|
||||||
let args_len = call_args.len() + fn_ptr.curry().len();
|
let args_len = call_args.len() + fn_ptr.curry().len();
|
||||||
// Recalculate hashes
|
// Recalculate hashes
|
||||||
let new_hash = FnHash::from_script(calc_fn_hash(empty(), fn_name, args_len));
|
let new_hash = FnCallHash::from_script(calc_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<_>>();
|
||||||
let mut arg_values = curry
|
let mut arg_values = curry
|
||||||
@ -949,7 +949,7 @@ impl Engine {
|
|||||||
let fn_name = fn_ptr.fn_name();
|
let fn_name = fn_ptr.fn_name();
|
||||||
let args_len = call_args.len() + fn_ptr.curry().len();
|
let args_len = call_args.len() + fn_ptr.curry().len();
|
||||||
// Recalculate hash
|
// Recalculate hash
|
||||||
let new_hash = FnHash::from_script_and_native(
|
let new_hash = FnCallHash::from_script_and_native(
|
||||||
calc_fn_hash(empty(), fn_name, args_len),
|
calc_fn_hash(empty(), fn_name, args_len),
|
||||||
calc_fn_hash(empty(), fn_name, args_len + 1),
|
calc_fn_hash(empty(), fn_name, args_len + 1),
|
||||||
);
|
);
|
||||||
@ -1024,7 +1024,7 @@ impl Engine {
|
|||||||
call_arg_positions.insert(i, Position::NONE);
|
call_arg_positions.insert(i, Position::NONE);
|
||||||
});
|
});
|
||||||
// Recalculate the hash based on the new function name and new arguments
|
// Recalculate the hash based on the new function name and new arguments
|
||||||
hash = FnHash::from_script_and_native(
|
hash = FnCallHash::from_script_and_native(
|
||||||
calc_fn_hash(empty(), fn_name, call_args.len()),
|
calc_fn_hash(empty(), fn_name, call_args.len()),
|
||||||
calc_fn_hash(empty(), fn_name, call_args.len() + 1),
|
calc_fn_hash(empty(), fn_name, call_args.len() + 1),
|
||||||
);
|
);
|
||||||
@ -1062,7 +1062,7 @@ impl Engine {
|
|||||||
this_ptr: &mut Option<&mut Dynamic>,
|
this_ptr: &mut Option<&mut Dynamic>,
|
||||||
fn_name: &str,
|
fn_name: &str,
|
||||||
args_expr: &[Expr],
|
args_expr: &[Expr],
|
||||||
mut hash: FnHash,
|
mut hash: FnCallHash,
|
||||||
pos: Position,
|
pos: Position,
|
||||||
capture_scope: bool,
|
capture_scope: bool,
|
||||||
level: usize,
|
level: usize,
|
||||||
@ -1101,9 +1101,9 @@ impl Engine {
|
|||||||
// Recalculate hash
|
// Recalculate hash
|
||||||
let args_len = args_expr.len() + curry.len();
|
let args_len = args_expr.len() + curry.len();
|
||||||
hash = if !hash.is_native_only() {
|
hash = if !hash.is_native_only() {
|
||||||
FnHash::from_script(calc_fn_hash(empty(), name, args_len))
|
FnCallHash::from_script(calc_fn_hash(empty(), name, args_len))
|
||||||
} else {
|
} else {
|
||||||
FnHash::from_native(calc_fn_hash(empty(), name, args_len))
|
FnCallHash::from_native(calc_fn_hash(empty(), name, args_len))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// Handle Fn()
|
// Handle Fn()
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//! Module defining interfaces to native-Rust functions.
|
//! Module defining interfaces to native-Rust functions.
|
||||||
|
|
||||||
use crate::ast::{FnAccess, FnHash};
|
use crate::ast::{FnAccess, FnCallHash};
|
||||||
use crate::engine::Imports;
|
use crate::engine::Imports;
|
||||||
use crate::plugin::PluginFunction;
|
use crate::plugin::PluginFunction;
|
||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
@ -190,12 +190,12 @@ impl<'a> NativeCallContext<'a> {
|
|||||||
args: &mut [&mut Dynamic],
|
args: &mut [&mut Dynamic],
|
||||||
) -> RhaiResult {
|
) -> RhaiResult {
|
||||||
let hash = if is_method {
|
let hash = if is_method {
|
||||||
FnHash::from_script_and_native(
|
FnCallHash::from_script_and_native(
|
||||||
calc_fn_hash(empty(), fn_name, args.len() - 1),
|
calc_fn_hash(empty(), fn_name, args.len() - 1),
|
||||||
calc_fn_hash(empty(), fn_name, args.len()),
|
calc_fn_hash(empty(), fn_name, args.len()),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
FnHash::from_script(calc_fn_hash(empty(), fn_name, args.len()))
|
FnCallHash::from_script(calc_fn_hash(empty(), fn_name, args.len()))
|
||||||
};
|
};
|
||||||
|
|
||||||
self.engine()
|
self.engine()
|
||||||
|
71
src/lib.rs
71
src/lib.rs
@ -191,8 +191,8 @@ pub use token::{get_next_token, parse_string_literal, InputStream, Token, Tokeni
|
|||||||
#[cfg(feature = "internals")]
|
#[cfg(feature = "internals")]
|
||||||
#[deprecated = "this type is volatile and may change"]
|
#[deprecated = "this type is volatile and may change"]
|
||||||
pub use ast::{
|
pub use ast::{
|
||||||
ASTNode, BinaryExpr, CustomExpr, Expr, FloatWrapper, FnCallExpr, FnHash, Ident, OpAssignment,
|
ASTNode, BinaryExpr, CustomExpr, Expr, FloatWrapper, FnCallExpr, FnCallHash, Ident,
|
||||||
ReturnType, ScriptFnDef, Stmt, StmtBlock,
|
OpAssignment, ReturnType, ScriptFnDef, Stmt, StmtBlock,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "internals")]
|
#[cfg(feature = "internals")]
|
||||||
@ -207,15 +207,72 @@ pub use engine::Limits;
|
|||||||
#[deprecated = "this type is volatile and may change"]
|
#[deprecated = "this type is volatile and may change"]
|
||||||
pub use module::NamespaceRef;
|
pub use module::NamespaceRef;
|
||||||
|
|
||||||
/// _(INTERNALS)_ Alias to [`smallvec::SmallVec<[T; 4]>`](https://crates.io/crates/smallvec),
|
/// Alias to [`smallvec::SmallVec<[T; 4]>`](https://crates.io/crates/smallvec), which is a
|
||||||
/// which is a specialized [`Vec`] backed by a small, fixed-size array when there are <= 4 items stored.
|
/// specialized [`Vec`] backed by a small, inline, fixed-size array when there are <= 4 items stored.
|
||||||
/// Exported under the `internals` feature only.
|
///
|
||||||
|
/// # Background
|
||||||
|
///
|
||||||
|
/// And Saint Attila raised the `SmallVec` up on high, saying, "O Lord, bless this Thy `SmallVec`
|
||||||
|
/// that, with it, Thou mayest blow Thine allocation costs to tiny bits in Thy mercy."
|
||||||
|
///
|
||||||
|
/// And the Lord did grin, and the people did feast upon the lambs and sloths and carp and anchovies
|
||||||
|
/// and orangutans and breakfast cereals and fruit bats and large chu...
|
||||||
|
///
|
||||||
|
/// And the Lord spake, saying, "First shalt thou depend on the [`smallvec`](https://crates.io/crates/smallvec) crate.
|
||||||
|
/// Then, shalt thou keep four inline. No more. No less. Four shalt be the number thou shalt keep inline,
|
||||||
|
/// and the number to keep inline shalt be four. Five shalt thou not keep inline, nor either keep inline
|
||||||
|
/// thou two or three, excepting that thou then proceed to four. Six is right out. Once the number four,
|
||||||
|
/// being the forth number, be reached, then, lobbest thou thy `SmallVec` towards thy heap, who,
|
||||||
|
/// being slow and cache-naughty in My sight, shall snuff it."
|
||||||
|
///
|
||||||
|
/// # Explanation on the Number Four
|
||||||
|
///
|
||||||
|
/// `StaticVec` is used frequently to keep small lists of items in inline (non-heap) storage in
|
||||||
|
/// order to improve cache friendliness and reduce indirections.
|
||||||
|
///
|
||||||
|
/// The number 4, other than being the holy number, is carefully chosen for a balance between
|
||||||
|
/// storage space and reduce allocations. That is because most function calls (and most functions,
|
||||||
|
/// in that matter) contain fewer than 5 arguments, the exception being closures that capture a
|
||||||
|
/// large number of external variables.
|
||||||
|
///
|
||||||
|
/// In addition, most scripts blocks either contain many statements, or just a few lines;
|
||||||
|
/// most scripts load fewer than 5 external modules; most module paths contain fewer than 5 levels
|
||||||
|
/// (e.g. `std::collections::map::HashMap` is 4 levels, and that's already quite long).
|
||||||
#[cfg(not(feature = "internals"))]
|
#[cfg(not(feature = "internals"))]
|
||||||
type StaticVec<T> = smallvec::SmallVec<[T; 4]>;
|
type StaticVec<T> = smallvec::SmallVec<[T; 4]>;
|
||||||
|
|
||||||
/// _(INTERNALS)_ Alias to [`smallvec::SmallVec<[T; 4]>`](https://crates.io/crates/smallvec),
|
/// _(INTERNALS)_ Alias to [`smallvec`](https://crates.io/crates/smallvec), which is a specialized
|
||||||
/// which is a specialized [`Vec`] backed by a small, fixed-size array when there are <= 4 items stored.
|
/// [`Vec`] backed by a small, inline, fixed-size array when there are <= 4 items stored.
|
||||||
/// Exported under the `internals` feature only.
|
/// Exported under the `internals` feature only.
|
||||||
|
///
|
||||||
|
/// # Background
|
||||||
|
///
|
||||||
|
/// And Saint Attila raised the `SmallVec` up on high, saying, "O Lord, bless this Thy `SmallVec`
|
||||||
|
/// that, with it, Thou mayest blow Thine allocation costs to tiny bits in Thy mercy."
|
||||||
|
///
|
||||||
|
/// And the Lord did grin, and the people did feast upon the lambs and sloths and carp and anchovies
|
||||||
|
/// and orangutans and breakfast cereals and fruit bats and large chu...
|
||||||
|
///
|
||||||
|
/// And the Lord spake, saying, "First shalt thou depend on the [`smallvec`](https://crates.io/crates/smallvec) crate.
|
||||||
|
/// Then, shalt thou keep four inline. No more. No less. Four shalt be the number thou shalt keep inline,
|
||||||
|
/// and the number to keep inline shalt be four. Five shalt thou not keep inline, nor either keep inline
|
||||||
|
/// thou two or three, excepting that thou then proceed to four. Six is right out. Once the number four,
|
||||||
|
/// being the forth number, be reached, then, lobbest thou thy `SmallVec` towards thy heap, who,
|
||||||
|
/// being slow and cache-naughty in My sight, shall snuff it."
|
||||||
|
///
|
||||||
|
/// # Explanation on the Number Four
|
||||||
|
///
|
||||||
|
/// `StaticVec` is used frequently to keep small lists of items in inline (non-heap) storage in
|
||||||
|
/// order to improve cache friendliness and reduce indirections.
|
||||||
|
///
|
||||||
|
/// The number 4, other than being the holy number, is carefully chosen for a balance between
|
||||||
|
/// storage space and reduce allocations. That is because most function calls (and most functions,
|
||||||
|
/// in that matter) contain fewer than 5 arguments, the exception being closures that capture a
|
||||||
|
/// large number of external variables.
|
||||||
|
///
|
||||||
|
/// In addition, most scripts blocks either contain many statements, or just a few lines;
|
||||||
|
/// most scripts load fewer than 5 external modules; most module paths contain fewer than 5 levels
|
||||||
|
/// (e.g. `std::collections::map::HashMap` is 4 levels, and that's already quite long).
|
||||||
#[cfg(feature = "internals")]
|
#[cfg(feature = "internals")]
|
||||||
pub type StaticVec<T> = smallvec::SmallVec<[T; 4]>;
|
pub type StaticVec<T> = smallvec::SmallVec<[T; 4]>;
|
||||||
|
|
||||||
|
@ -1398,12 +1398,14 @@ impl Module {
|
|||||||
|
|
||||||
scope.into_iter().for_each(|(_, value, mut aliases)| {
|
scope.into_iter().for_each(|(_, value, mut aliases)| {
|
||||||
// Variables with an alias left in the scope become module variables
|
// Variables with an alias left in the scope become module variables
|
||||||
if aliases.len() > 1 {
|
match aliases.len() {
|
||||||
aliases.into_iter().for_each(|alias| {
|
0 => (),
|
||||||
|
1 => {
|
||||||
|
module.variables.insert(aliases.pop().unwrap(), value);
|
||||||
|
}
|
||||||
|
_ => aliases.into_iter().for_each(|alias| {
|
||||||
module.variables.insert(alias, value.clone());
|
module.variables.insert(alias, value.clone());
|
||||||
});
|
}),
|
||||||
} else if aliases.len() == 1 {
|
|
||||||
module.variables.insert(aliases.pop().unwrap(), value);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -108,8 +108,8 @@ fn collect_fn_metadata(ctx: NativeCallContext) -> crate::Array {
|
|||||||
list.push(make_metadata(dict, Some(namespace.clone()), f).into())
|
list.push(make_metadata(dict, Some(namespace.clone()), f).into())
|
||||||
});
|
});
|
||||||
module.iter_sub_modules().for_each(|(ns, m)| {
|
module.iter_sub_modules().for_each(|(ns, m)| {
|
||||||
let ns: ImmutableString = format!("{}::{}", namespace, ns).into();
|
let ns = format!("{}::{}", namespace, ns);
|
||||||
scan_module(list, dict, ns, m.as_ref())
|
scan_module(list, dict, ns.into(), m.as_ref())
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,15 +29,11 @@ mod map_functions {
|
|||||||
}
|
}
|
||||||
#[rhai_fn(name = "mixin", name = "+=")]
|
#[rhai_fn(name = "mixin", name = "+=")]
|
||||||
pub fn mixin(map: &mut Map, map2: Map) {
|
pub fn mixin(map: &mut Map, map2: Map) {
|
||||||
map2.into_iter().for_each(|(key, value)| {
|
map.extend(map2.into_iter());
|
||||||
map.insert(key, value);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "+")]
|
#[rhai_fn(name = "+")]
|
||||||
pub fn merge(mut map: Map, map2: Map) -> Map {
|
pub fn merge(mut map: Map, map2: Map) -> Map {
|
||||||
map2.into_iter().for_each(|(key, value)| {
|
map.extend(map2.into_iter());
|
||||||
map.insert(key, value);
|
|
||||||
});
|
|
||||||
map
|
map
|
||||||
}
|
}
|
||||||
pub fn fill_with(map: &mut Map, map2: Map) {
|
pub fn fill_with(map: &mut Map, map2: Map) {
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
//! Main module defining the lexer and parser.
|
//! Main module defining the lexer and parser.
|
||||||
|
|
||||||
use crate::ast::{
|
use crate::ast::{
|
||||||
BinaryExpr, CustomExpr, Expr, FnCallExpr, FnHash, Ident, OpAssignment, ReturnType, ScriptFnDef,
|
BinaryExpr, CustomExpr, Expr, FnCallExpr, FnCallHash, Ident, OpAssignment, ReturnType,
|
||||||
Stmt, StmtBlock,
|
ScriptFnDef, Stmt, StmtBlock,
|
||||||
};
|
};
|
||||||
use crate::dynamic::{AccessMode, Union};
|
use crate::dynamic::{AccessMode, Union};
|
||||||
use crate::engine::{Precedence, KEYWORD_THIS, OP_CONTAINS};
|
use crate::engine::{Precedence, KEYWORD_THIS, OP_CONTAINS};
|
||||||
@ -359,9 +359,9 @@ fn parse_fn_call(
|
|||||||
capture,
|
capture,
|
||||||
namespace,
|
namespace,
|
||||||
hash: if is_valid_identifier(id.chars()) {
|
hash: if is_valid_identifier(id.chars()) {
|
||||||
FnHash::from_script(hash)
|
FnCallHash::from_script(hash)
|
||||||
} else {
|
} else {
|
||||||
FnHash::from_native(hash)
|
FnCallHash::from_native(hash)
|
||||||
},
|
},
|
||||||
args,
|
args,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@ -402,9 +402,9 @@ fn parse_fn_call(
|
|||||||
capture,
|
capture,
|
||||||
namespace,
|
namespace,
|
||||||
hash: if is_valid_identifier(id.chars()) {
|
hash: if is_valid_identifier(id.chars()) {
|
||||||
FnHash::from_script(hash)
|
FnCallHash::from_script(hash)
|
||||||
} else {
|
} else {
|
||||||
FnHash::from_native(hash)
|
FnCallHash::from_native(hash)
|
||||||
},
|
},
|
||||||
args,
|
args,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@ -1291,7 +1291,7 @@ fn parse_unary(
|
|||||||
Ok(Expr::FnCall(
|
Ok(Expr::FnCall(
|
||||||
Box::new(FnCallExpr {
|
Box::new(FnCallExpr {
|
||||||
name: op.into(),
|
name: op.into(),
|
||||||
hash: FnHash::from_native(calc_fn_hash(empty(), op, 1)),
|
hash: FnCallHash::from_native(calc_fn_hash(empty(), op, 1)),
|
||||||
args,
|
args,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
@ -1318,7 +1318,7 @@ fn parse_unary(
|
|||||||
Ok(Expr::FnCall(
|
Ok(Expr::FnCall(
|
||||||
Box::new(FnCallExpr {
|
Box::new(FnCallExpr {
|
||||||
name: op.into(),
|
name: op.into(),
|
||||||
hash: FnHash::from_native(calc_fn_hash(empty(), op, 1)),
|
hash: FnCallHash::from_native(calc_fn_hash(empty(), op, 1)),
|
||||||
args,
|
args,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
@ -1339,7 +1339,7 @@ fn parse_unary(
|
|||||||
Ok(Expr::FnCall(
|
Ok(Expr::FnCall(
|
||||||
Box::new(FnCallExpr {
|
Box::new(FnCallExpr {
|
||||||
name: op.into(),
|
name: op.into(),
|
||||||
hash: FnHash::from_native(calc_fn_hash(empty(), op, 1)),
|
hash: FnCallHash::from_native(calc_fn_hash(empty(), op, 1)),
|
||||||
args,
|
args,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
@ -1538,7 +1538,7 @@ fn make_dot_expr(
|
|||||||
}
|
}
|
||||||
Expr::FnCall(mut func, func_pos) => {
|
Expr::FnCall(mut func, func_pos) => {
|
||||||
// Recalculate hash
|
// Recalculate hash
|
||||||
func.hash = FnHash::from_script_and_native(
|
func.hash = FnCallHash::from_script_and_native(
|
||||||
calc_fn_hash(empty(), &func.name, func.args.len()),
|
calc_fn_hash(empty(), &func.name, func.args.len()),
|
||||||
calc_fn_hash(empty(), &func.name, func.args.len() + 1),
|
calc_fn_hash(empty(), &func.name, func.args.len() + 1),
|
||||||
);
|
);
|
||||||
@ -1594,7 +1594,7 @@ fn make_dot_expr(
|
|||||||
// lhs.func(...)
|
// lhs.func(...)
|
||||||
(lhs, Expr::FnCall(mut func, func_pos)) => {
|
(lhs, Expr::FnCall(mut func, func_pos)) => {
|
||||||
// Recalculate hash
|
// Recalculate hash
|
||||||
func.hash = FnHash::from_script_and_native(
|
func.hash = FnCallHash::from_script_and_native(
|
||||||
calc_fn_hash(empty(), &func.name, func.args.len()),
|
calc_fn_hash(empty(), &func.name, func.args.len()),
|
||||||
calc_fn_hash(empty(), &func.name, func.args.len() + 1),
|
calc_fn_hash(empty(), &func.name, func.args.len() + 1),
|
||||||
);
|
);
|
||||||
@ -1682,7 +1682,7 @@ fn parse_binary_op(
|
|||||||
|
|
||||||
let op_base = FnCallExpr {
|
let op_base = FnCallExpr {
|
||||||
name: op,
|
name: op,
|
||||||
hash: FnHash::from_native(hash),
|
hash: FnCallHash::from_native(hash),
|
||||||
capture: false,
|
capture: false,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
@ -1747,7 +1747,7 @@ fn parse_binary_op(
|
|||||||
let hash = calc_fn_hash(empty(), OP_CONTAINS, 2);
|
let hash = calc_fn_hash(empty(), OP_CONTAINS, 2);
|
||||||
Expr::FnCall(
|
Expr::FnCall(
|
||||||
Box::new(FnCallExpr {
|
Box::new(FnCallExpr {
|
||||||
hash: FnHash::from_script(hash),
|
hash: FnCallHash::from_script(hash),
|
||||||
args,
|
args,
|
||||||
name: OP_CONTAINS.into(),
|
name: OP_CONTAINS.into(),
|
||||||
..op_base
|
..op_base
|
||||||
@ -1768,9 +1768,9 @@ fn parse_binary_op(
|
|||||||
Expr::FnCall(
|
Expr::FnCall(
|
||||||
Box::new(FnCallExpr {
|
Box::new(FnCallExpr {
|
||||||
hash: if is_valid_identifier(s.chars()) {
|
hash: if is_valid_identifier(s.chars()) {
|
||||||
FnHash::from_script(hash)
|
FnCallHash::from_script(hash)
|
||||||
} else {
|
} else {
|
||||||
FnHash::from_native(hash)
|
FnCallHash::from_native(hash)
|
||||||
},
|
},
|
||||||
args,
|
args,
|
||||||
..op_base
|
..op_base
|
||||||
@ -2783,7 +2783,7 @@ fn make_curry_from_externals(fn_expr: Expr, externals: StaticVec<Ident>, pos: Po
|
|||||||
let expr = Expr::FnCall(
|
let expr = Expr::FnCall(
|
||||||
Box::new(FnCallExpr {
|
Box::new(FnCallExpr {
|
||||||
name: curry_func.into(),
|
name: curry_func.into(),
|
||||||
hash: FnHash::from_native(calc_fn_hash(empty(), curry_func, num_externals + 1)),
|
hash: FnCallHash::from_native(calc_fn_hash(empty(), curry_func, num_externals + 1)),
|
||||||
args,
|
args,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
@ -2884,7 +2884,7 @@ fn parse_anon_fn(
|
|||||||
|
|
||||||
// Create unique function name by hashing the script body plus the parameters.
|
// Create unique function name by hashing the script body plus the parameters.
|
||||||
let hasher = &mut get_hasher();
|
let hasher = &mut get_hasher();
|
||||||
params.iter().for_each(|p| p.as_str().hash(hasher));
|
params.iter().for_each(|p| p.hash(hasher));
|
||||||
body.hash(hasher);
|
body.hash(hasher);
|
||||||
let hash = hasher.finish();
|
let hash = hasher.finish();
|
||||||
|
|
||||||
|
@ -434,10 +434,10 @@ impl<'a> Scope<'a> {
|
|||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.rev()
|
.rev()
|
||||||
.for_each(|(index, (name, alias))| {
|
.for_each(|(i, (name, alias))| {
|
||||||
if !entries.names.iter().any(|(key, _)| key == name) {
|
if !entries.names.iter().any(|(key, _)| key == name) {
|
||||||
entries.names.push((name.clone(), alias.clone()));
|
entries.names.push((name.clone(), alias.clone()));
|
||||||
entries.values.push(self.values[index].clone());
|
entries.values.push(self.values[i].clone());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -228,8 +228,8 @@ impl Engine {
|
|||||||
if include_global {
|
if include_global {
|
||||||
self.global_modules
|
self.global_modules
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|m| m.iter_fn().map(|f| f.into()))
|
.flat_map(|m| m.iter_fn())
|
||||||
.for_each(|info| global.functions.push(info));
|
.for_each(|f| global.functions.push(f.into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
self.global_sub_modules.iter().for_each(|(name, m)| {
|
self.global_sub_modules.iter().for_each(|(name, m)| {
|
||||||
@ -238,13 +238,11 @@ impl Engine {
|
|||||||
|
|
||||||
self.global_namespace
|
self.global_namespace
|
||||||
.iter_fn()
|
.iter_fn()
|
||||||
.map(|f| f.into())
|
.for_each(|f| global.functions.push(f.into()));
|
||||||
.for_each(|info| global.functions.push(info));
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
_ast.iter_functions()
|
_ast.iter_functions()
|
||||||
.map(|f| f.into())
|
.for_each(|f| global.functions.push(f.into()));
|
||||||
.for_each(|info| global.functions.push(info));
|
|
||||||
|
|
||||||
global.functions.sort();
|
global.functions.sort();
|
||||||
|
|
||||||
|
20
src/utils.rs
20
src/utils.rs
@ -72,17 +72,16 @@ pub fn get_hasher() -> ahash::AHasher {
|
|||||||
///
|
///
|
||||||
/// 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.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn calc_fn_hash<'a>(
|
pub fn calc_fn_hash<'a>(modules: impl Iterator<Item = &'a str>, fn_name: &str, num: usize) -> u64 {
|
||||||
mut modules: impl Iterator<Item = &'a str>,
|
|
||||||
fn_name: &str,
|
|
||||||
num: usize,
|
|
||||||
) -> u64 {
|
|
||||||
let s = &mut get_hasher();
|
let s = &mut get_hasher();
|
||||||
|
|
||||||
// Hash a boolean indicating whether the hash is namespace-qualified.
|
|
||||||
modules.next().is_some().hash(s);
|
|
||||||
// We always skip the first module
|
// We always skip the first module
|
||||||
modules.for_each(|m| m.hash(s));
|
let mut len = 0;
|
||||||
|
modules
|
||||||
|
.inspect(|_| len += 1)
|
||||||
|
.skip(1)
|
||||||
|
.for_each(|m| m.hash(s));
|
||||||
|
len.hash(s);
|
||||||
fn_name.hash(s);
|
fn_name.hash(s);
|
||||||
num.hash(s);
|
num.hash(s);
|
||||||
s.finish()
|
s.finish()
|
||||||
@ -96,10 +95,7 @@ pub fn calc_fn_hash<'a>(
|
|||||||
pub fn calc_fn_params_hash(params: impl Iterator<Item = TypeId>) -> u64 {
|
pub fn calc_fn_params_hash(params: impl Iterator<Item = TypeId>) -> u64 {
|
||||||
let s = &mut get_hasher();
|
let s = &mut get_hasher();
|
||||||
let mut len = 0;
|
let mut len = 0;
|
||||||
params.for_each(|t| {
|
params.inspect(|_| len += 1).for_each(|t| t.hash(s));
|
||||||
t.hash(s);
|
|
||||||
len += 1;
|
|
||||||
});
|
|
||||||
len.hash(s);
|
len.hash(s);
|
||||||
s.finish()
|
s.finish()
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user