Refine data structures.

This commit is contained in:
Stephen Chung 2022-05-07 15:54:44 +08:00
parent fc64e93b93
commit 4194e2c048
8 changed files with 59 additions and 41 deletions

View File

@ -8,7 +8,7 @@ use crate::tokenizer::{is_valid_identifier, Token};
use crate::types::dynamic::Variant;
use crate::{
reify, Engine, EvalContext, Identifier, ImmutableString, LexError, Position, RhaiResult,
Shared, StaticVec,
StaticVec,
};
use std::ops::Deref;
#[cfg(feature = "no_std")]
@ -65,6 +65,15 @@ impl<'a> From<&'a Expr> for Expression<'a> {
}
impl Expression<'_> {
/// Evaluate this [expression tree][Expression] within an [evaluation context][`EvalContext`].
///
/// # WARNING - Low Level API
///
/// This function is very low level. It evaluates an expression from an [`AST`][crate::AST].
#[inline(always)]
pub fn eval_with_context(&self, context: &mut EvalContext) -> RhaiResult {
context.eval_expression_tree(self)
}
/// Get the value of this expression if it is a variable name or a string constant.
///
/// Returns [`None`] also if the constant is not of the specified type.
@ -132,7 +141,7 @@ impl Deref for Expression<'_> {
}
impl EvalContext<'_, '_, '_, '_, '_, '_, '_, '_> {
/// Evaluate an [expression tree][Expression].
/// Evaluate an [expression tree][Expression] within this [evaluation context][`EvalContext`].
///
/// # WARNING - Low Level API
///
@ -165,7 +174,7 @@ pub struct CustomSyntax {
/// symbols parsed so far.
pub parse: Box<FnCustomSyntaxParse>,
/// Custom syntax implementation function.
pub func: Shared<FnCustomSyntaxEval>,
pub func: Box<FnCustomSyntaxEval>,
/// Any variables added/removed in the scope?
pub scope_may_be_changed: bool,
}
@ -356,7 +365,7 @@ impl Engine {
key.into(),
CustomSyntax {
parse: Box::new(parse),
func: (Box::new(func) as Box<FnCustomSyntaxEval>).into(),
func: Box::new(func),
scope_may_be_changed,
}
.into(),

View File

@ -119,8 +119,8 @@ impl Engine {
},
);
let scope = &Scope::new();
let mut state = ParseState::new(self, scope, tokenizer_control);
let scope = Scope::new();
let mut state = ParseState::new(self, &scope, tokenizer_control);
let ast = self.parse_global_expr(
&mut stream.peekable(),

View File

@ -112,7 +112,7 @@ pub struct Engine {
/// A map containing custom keywords and precedence to recognize.
pub(crate) custom_keywords: BTreeMap<Identifier, Option<Precedence>>,
/// Custom syntax.
pub(crate) custom_syntax: BTreeMap<Identifier, Box<CustomSyntax>>,
pub(crate) custom_syntax: BTreeMap<Identifier, CustomSyntax>,
/// Callback closure for filtering variable definition.
pub(crate) def_var_filter: Option<Box<OnDefVarCallback>>,
/// Callback closure for resolving variable access.
@ -155,7 +155,14 @@ impl fmt::Debug for Engine {
f.field("disabled_symbols", &self.disabled_symbols)
.field("custom_keywords", &self.custom_keywords)
.field("custom_syntax", &(!self.custom_syntax.is_empty()))
.field(
"custom_syntax",
&self
.custom_syntax
.keys()
.map(|s| s.as_str())
.collect::<String>(),
)
.field("def_var_filter", &self.def_var_filter.is_some())
.field("resolve_var", &self.resolve_var.is_some())
.field("token_mapper", &self.token_mapper.is_some());

View File

@ -13,8 +13,7 @@ pub struct FnResolutionCacheEntry {
/// Function.
pub func: CallableFunction,
/// Optional source.
/// No source if the string is empty.
pub source: Identifier,
pub source: Option<Box<Identifier>>,
}
/// _(internals)_ A function resolution cache.
@ -22,7 +21,7 @@ pub struct FnResolutionCacheEntry {
///
/// [`FnResolutionCacheEntry`] is [`Box`]ed in order to pack as many entries inside a single B-Tree
/// level as possible.
pub type FnResolutionCache = BTreeMap<u64, Option<Box<FnResolutionCacheEntry>>>;
pub type FnResolutionCache = BTreeMap<u64, Option<FnResolutionCacheEntry>>;
/// _(internals)_ A type containing system-wide caches.
/// Exported under the `internals` feature only.

View File

@ -7,13 +7,13 @@ use std::prelude::v1::*;
/// Context of a script evaluation process.
#[derive(Debug)]
pub struct EvalContext<'a, 's, 'ps, 'm, 'pm, 'c, 't, 'pt> {
pub struct EvalContext<'a, 's, 'ps, 'g, 'pg, 'c, 't, 'pt> {
/// The current [`Engine`].
pub(crate) engine: &'a Engine,
/// The current [`Scope`].
pub(crate) scope: &'s mut Scope<'ps>,
/// The current [`GlobalRuntimeState`].
pub(crate) global: &'m mut GlobalRuntimeState<'pm>,
pub(crate) global: &'g mut GlobalRuntimeState<'pg>,
/// The current [caches][Caches], if available.
pub(crate) caches: Option<&'c mut Caches>,
/// The current stack of imported [modules][Module].
@ -24,7 +24,7 @@ pub struct EvalContext<'a, 's, 'ps, 'm, 'pm, 'c, 't, 'pt> {
pub(crate) level: usize,
}
impl<'s, 'ps, 'm, 'pm, 'pt> EvalContext<'_, 's, 'ps, 'm, 'pm, '_, '_, 'pt> {
impl<'s, 'ps, 'g, 'pg, 'pt> EvalContext<'_, 's, 'ps, 'g, 'pg, '_, '_, 'pt> {
/// The current [`Engine`].
#[inline(always)]
#[must_use]
@ -85,7 +85,7 @@ impl<'s, 'ps, 'm, 'pm, 'pt> EvalContext<'_, 's, 'ps, 'm, 'pm, '_, '_, 'pt> {
#[cfg(feature = "internals")]
#[inline(always)]
#[must_use]
pub fn global_runtime_state_mut(&mut self) -> &mut &'m mut GlobalRuntimeState<'pm> {
pub fn global_runtime_state_mut(&mut self) -> &mut &'g mut GlobalRuntimeState<'pg> {
&mut self.global
}
/// Get an iterator over the namespaces containing definition of all script-defined functions.

View File

@ -214,14 +214,14 @@ impl Engine {
.find_map(|&m| {
m.get_fn(hash).cloned().map(|func| FnResolutionCacheEntry {
func,
source: m.id_raw().clone(),
source: m.id().map(|s| Box::new(s.into())),
})
})
.or_else(|| {
self.global_modules.iter().find_map(|m| {
m.get_fn(hash).cloned().map(|func| FnResolutionCacheEntry {
func,
source: m.id_raw().clone(),
source: m.id().map(|s| Box::new(s.into())),
})
})
});
@ -232,8 +232,7 @@ impl Engine {
_global.get_qualified_fn(hash).map(|(func, source)| {
FnResolutionCacheEntry {
func: func.clone(),
source: source
.map_or_else(|| Identifier::new_const(), Into::into),
source: source.map(|s| Box::new(s.into())),
}
})
})
@ -242,7 +241,7 @@ impl Engine {
m.get_qualified_fn(hash).cloned().map(|func| {
FnResolutionCacheEntry {
func,
source: m.id_raw().clone(),
source: m.id().map(|s| Box::new(s.into())),
}
})
})
@ -250,7 +249,7 @@ impl Engine {
match func {
// Specific version found
Some(f) => return Some(Box::new(f)),
Some(f) => return Some(f),
// Stop when all permutations are exhausted
None if bitmask >= max_bitmask => {
@ -265,7 +264,7 @@ impl Engine {
func: CallableFunction::from_method(
Box::new(f) as Box<FnAny>
),
source: Identifier::new_const(),
source: None,
}
})
} else {
@ -276,10 +275,9 @@ impl Engine {
func: CallableFunction::from_method(
Box::new(f) as Box<FnAny>
),
source: Identifier::new_const(),
source: None,
})
}
.map(Box::new)
});
}
@ -308,7 +306,7 @@ impl Engine {
}
});
result.as_ref().map(Box::as_ref)
result.as_ref()
}
/// # Main Entry-Point
@ -370,9 +368,10 @@ impl Engine {
backup.change_first_arg_to_copy(args);
}
let source = match (source.as_str(), parent_source.as_str()) {
("", "") => None,
("", s) | (s, ..) => Some(s),
let source = match (source, parent_source.as_str()) {
(None, "") => None,
(None, s) => Some(s),
(Some(s), ..) => Some(s.as_str()),
};
#[cfg(feature = "debugging")]
@ -626,7 +625,7 @@ impl Engine {
// Script-defined function call?
#[cfg(not(feature = "no_function"))]
if let Some(FnResolutionCacheEntry { func, mut source }) = self
if let Some(FnResolutionCacheEntry { func, ref source }) = self
.resolve_fn(
global,
caches,
@ -657,7 +656,13 @@ impl Engine {
}
};
mem::swap(&mut global.source, &mut source);
let orig_source = mem::replace(
&mut global.source,
source
.as_ref()
.map(|s| (**s).clone())
.unwrap_or(Identifier::new_const()),
);
let result = if _is_method_call {
// Method call of script function - map first argument to `this`
@ -695,7 +700,7 @@ impl Engine {
};
// Restore the original source
mem::swap(&mut global.source, &mut source);
global.source = orig_source;
return Ok((result?, false));
}
@ -757,7 +762,7 @@ impl Engine {
// Recalculate hashes
let new_hash = calc_fn_hash(fn_name, args_len).into();
// Arguments are passed as-is, adding the curried arguments
let mut curry = FnArgsVec::with_capacity(fn_ptr.num_curried());
let mut curry = FnArgsVec::with_capacity(fn_ptr.curry().len());
curry.extend(fn_ptr.curry().iter().cloned());
let mut args = FnArgsVec::with_capacity(curry.len() + call_args.len());
args.extend(curry.iter_mut());
@ -792,7 +797,7 @@ impl Engine {
calc_fn_hash(fn_name, args_len + 1),
);
// Replace the first argument with the object pointer, adding the curried arguments
let mut curry = FnArgsVec::with_capacity(fn_ptr.num_curried());
let mut curry = FnArgsVec::with_capacity(fn_ptr.curry().len());
curry.extend(fn_ptr.curry().iter().cloned());
let mut args = FnArgsVec::with_capacity(curry.len() + call_args.len() + 1);
args.push(target.as_mut());

View File

@ -44,7 +44,7 @@
//! # #[cfg(not(target_family = "wasm"))]
//! #
//! // Evaluate the script, expecting a 'bool' result
//! let result = engine.eval_file::<bool>("my_script.rhai".into())?;
//! let result: bool = engine.eval_file("my_script.rhai".into())?;
//!
//! assert_eq!(result, true);
//!

View File

@ -81,7 +81,7 @@ impl Ord for FnMetadata {
#[derive(Debug, Clone)]
pub struct FuncInfo {
/// Function instance.
pub func: Shared<CallableFunction>,
pub func: CallableFunction,
/// Parameter types (if applicable).
pub param_types: StaticVec<TypeId>,
/// Function metadata.
@ -246,7 +246,7 @@ pub struct Module {
functions: BTreeMap<u64, Box<FuncInfo>>,
/// Flattened collection of all external Rust functions, native or scripted.
/// including those in sub-modules.
all_functions: BTreeMap<u64, Shared<CallableFunction>>,
all_functions: BTreeMap<u64, CallableFunction>,
/// Iterator functions, keyed by the type producing the iterator.
type_iterators: BTreeMap<TypeId, Shared<IteratorFn>>,
/// Flattened collection of iterator functions, including those in sub-modules.
@ -1452,7 +1452,7 @@ impl Module {
#[must_use]
pub(crate) fn get_fn(&self, hash_fn: u64) -> Option<&CallableFunction> {
if !self.functions.is_empty() {
self.functions.get(&hash_fn).map(|f| f.func.as_ref())
self.functions.get(&hash_fn).map(|f| &f.func)
} else {
None
}
@ -1479,9 +1479,7 @@ impl Module {
#[must_use]
pub(crate) fn get_qualified_fn(&self, hash_qualified_fn: u64) -> Option<&CallableFunction> {
if !self.all_functions.is_empty() {
self.all_functions
.get(&hash_qualified_fn)
.map(|f| f.as_ref())
self.all_functions.get(&hash_qualified_fn)
} else {
None
}
@ -1932,7 +1930,7 @@ impl Module {
module: &'a Module,
path: &mut Vec<&'a str>,
variables: &mut BTreeMap<u64, Dynamic>,
functions: &mut BTreeMap<u64, Shared<CallableFunction>>,
functions: &mut BTreeMap<u64, CallableFunction>,
type_iterators: &mut BTreeMap<TypeId, Shared<IteratorFn>>,
) -> bool {
let mut contains_indexed_global_functions = false;