Optimize data structures.
This commit is contained in:
parent
c6ef2d1e95
commit
07a8a43298
63
src/ast.rs
63
src/ast.rs
@ -4,7 +4,7 @@ use crate::dynamic::{Dynamic, Union};
|
||||
use crate::fn_native::{FnPtr, Shared};
|
||||
use crate::module::{Module, ModuleRef};
|
||||
use crate::syntax::FnCustomSyntaxEval;
|
||||
use crate::token::{Position, Token};
|
||||
use crate::token::{Position, Token, NO_POS};
|
||||
use crate::utils::ImmutableString;
|
||||
use crate::StaticVec;
|
||||
use crate::INT;
|
||||
@ -93,9 +93,9 @@ pub struct ScriptFnDef {
|
||||
pub access: FnAccess,
|
||||
/// Names of function parameters.
|
||||
pub params: StaticVec<String>,
|
||||
/// Access to external variables.
|
||||
/// Access to external variables. Boxed because it occurs rarely.
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
pub externals: HashSet<String>,
|
||||
pub externals: Option<Box<HashSet<String>>>,
|
||||
}
|
||||
|
||||
impl fmt::Display for ScriptFnDef {
|
||||
@ -590,11 +590,12 @@ pub enum ReturnType {
|
||||
Exception,
|
||||
}
|
||||
|
||||
/// _[INTERNALS]_ A Rhai statement.
|
||||
/// _[INTERNALS]_ A statement.
|
||||
/// Exported under the `internals` feature only.
|
||||
///
|
||||
/// Each variant is at most one pointer in size (for speed),
|
||||
/// with everything being allocated together in one single tuple.
|
||||
/// ## WARNING
|
||||
///
|
||||
/// This type is volatile and may change.
|
||||
#[derive(Debug, Clone, Hash)]
|
||||
pub enum Stmt {
|
||||
/// No-op.
|
||||
@ -616,7 +617,7 @@ pub enum Stmt {
|
||||
/// { stmt; ... }
|
||||
Block(Vec<Stmt>, Position),
|
||||
/// try { stmt; ... } catch ( var ) { stmt; ... }
|
||||
TryCatch(Box<(Stmt, Option<Ident>, Stmt, (Position, Position))>),
|
||||
TryCatch(Box<(Stmt, Option<Ident>, Stmt)>, Position, Position),
|
||||
/// expr
|
||||
Expr(Expr),
|
||||
/// continue
|
||||
@ -639,7 +640,7 @@ pub enum Stmt {
|
||||
impl Default for Stmt {
|
||||
#[inline(always)]
|
||||
fn default() -> Self {
|
||||
Self::Noop(Default::default())
|
||||
Self::Noop(NO_POS)
|
||||
}
|
||||
}
|
||||
|
||||
@ -667,7 +668,7 @@ impl Stmt {
|
||||
| Self::ReturnWithVal((_, pos), _, _) => *pos,
|
||||
|
||||
Self::Let(x, _, _) | Self::Const(x, _, _) => x.pos,
|
||||
Self::TryCatch(x) => (x.3).0,
|
||||
Self::TryCatch(_, pos, _) => *pos,
|
||||
|
||||
Self::Expr(x) => x.position(),
|
||||
|
||||
@ -696,7 +697,7 @@ impl Stmt {
|
||||
| Self::ReturnWithVal((_, pos), _, _) => *pos = new_pos,
|
||||
|
||||
Self::Let(x, _, _) | Self::Const(x, _, _) => x.pos = new_pos,
|
||||
Self::TryCatch(x) => (x.3).0 = new_pos,
|
||||
Self::TryCatch(_, pos, _) => *pos = new_pos,
|
||||
|
||||
Self::Expr(x) => {
|
||||
x.set_position(new_pos);
|
||||
@ -722,7 +723,7 @@ impl Stmt {
|
||||
| Self::Loop(_, _)
|
||||
| Self::For(_, _, _)
|
||||
| Self::Block(_, _)
|
||||
| Self::TryCatch(_) => true,
|
||||
| Self::TryCatch(_, _, _) => true,
|
||||
|
||||
// A No-op requires a semicolon in order to know it is an empty statement!
|
||||
Self::Noop(_) => false,
|
||||
@ -758,7 +759,7 @@ impl Stmt {
|
||||
Self::Let(_, _, _) | Self::Const(_, _, _) | Self::Assignment(_, _) => false,
|
||||
Self::Block(block, _) => block.iter().all(|stmt| stmt.is_pure()),
|
||||
Self::Continue(_) | Self::Break(_) | Self::ReturnWithVal(_, _, _) => false,
|
||||
Self::TryCatch(x) => x.0.is_pure() && x.2.is_pure(),
|
||||
Self::TryCatch(x, _, _) => x.0.is_pure() && x.2.is_pure(),
|
||||
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
Self::Import(_, _, _) => false,
|
||||
@ -779,7 +780,9 @@ impl Stmt {
|
||||
/// This type is volatile and may change.
|
||||
#[derive(Clone)]
|
||||
pub struct CustomExpr {
|
||||
/// List of keywords.
|
||||
pub(crate) keywords: StaticVec<Expr>,
|
||||
/// Implementation function.
|
||||
pub(crate) func: Shared<FnCustomSyntaxEval>,
|
||||
}
|
||||
|
||||
@ -848,6 +851,11 @@ impl From<INT> for FloatWrapper {
|
||||
}
|
||||
|
||||
/// A binary expression structure.
|
||||
/// Exported under the `internals` feature only.
|
||||
///
|
||||
/// ## WARNING
|
||||
///
|
||||
/// This type is volatile and may change.
|
||||
#[derive(Debug, Clone, Hash)]
|
||||
pub struct BinaryExpr {
|
||||
/// LHS expression.
|
||||
@ -856,7 +864,12 @@ pub struct BinaryExpr {
|
||||
pub rhs: Expr,
|
||||
}
|
||||
|
||||
/// A function call.
|
||||
/// _[INTERNALS]_ A function call.
|
||||
/// Exported under the `internals` feature only.
|
||||
///
|
||||
/// ## WARNING
|
||||
///
|
||||
/// This type is volatile and may change.
|
||||
#[derive(Debug, Clone, Hash, Default)]
|
||||
pub struct FnCallInfo {
|
||||
/// Pre-calculated hash for a script-defined function of the same name and number of parameters.
|
||||
@ -869,7 +882,7 @@ pub struct FnCallInfo {
|
||||
/// Default value when the function is not found, mostly used to provide a default for comparison functions.
|
||||
/// Type is `bool` in order for `FnCallInfo` to be `Hash`
|
||||
pub def_value: Option<bool>,
|
||||
/// Namespace of the function, if any.
|
||||
/// Namespace of the function, if any. Boxed because it occurs rarely.
|
||||
pub namespace: Option<Box<ModuleRef>>,
|
||||
/// Function name.
|
||||
/// Use `Cow<'static, str>` because a lot of operators (e.g. `==`, `>=`) are implemented as function calls
|
||||
@ -882,9 +895,6 @@ pub struct FnCallInfo {
|
||||
/// _[INTERNALS]_ An expression sub-tree.
|
||||
/// Exported under the `internals` feature only.
|
||||
///
|
||||
/// Each variant is at most one pointer in size (for speed),
|
||||
/// with everything being allocated together in one single tuple.
|
||||
///
|
||||
/// ## WARNING
|
||||
///
|
||||
/// This type is volatile and may change.
|
||||
@ -938,7 +948,7 @@ pub enum Expr {
|
||||
impl Default for Expr {
|
||||
#[inline(always)]
|
||||
fn default() -> Self {
|
||||
Self::Unit(Default::default())
|
||||
Self::Unit(NO_POS)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1241,16 +1251,21 @@ impl Expr {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
/// This test is to make sure no code changes increase the sizes of critical data structures.
|
||||
#[test]
|
||||
fn check_struct_sizes() {
|
||||
use std::mem::size_of;
|
||||
|
||||
assert_eq!(size_of::<Dynamic>(), 16);
|
||||
assert_eq!(size_of::<Option<Dynamic>>(), 16);
|
||||
assert_eq!(size_of::<Expr>(), 16);
|
||||
assert_eq!(size_of::<Stmt>(), 32);
|
||||
assert_eq!(size_of::<crate::Dynamic>(), 16);
|
||||
assert_eq!(size_of::<Option<crate::Dynamic>>(), 16);
|
||||
assert_eq!(size_of::<crate::Position>(), 4);
|
||||
assert_eq!(size_of::<crate::ast::Expr>(), 16);
|
||||
assert_eq!(size_of::<Option<crate::ast::Expr>>(), 16);
|
||||
assert_eq!(size_of::<crate::ast::Stmt>(), 32);
|
||||
assert_eq!(size_of::<Option<crate::ast::Stmt>>(), 32);
|
||||
assert_eq!(size_of::<crate::Scope>(), 72);
|
||||
assert_eq!(size_of::<crate::LexError>(), 32);
|
||||
assert_eq!(size_of::<crate::ParseError>(), 16);
|
||||
assert_eq!(size_of::<crate::EvalAltResult>(), 64);
|
||||
}
|
||||
}
|
||||
|
@ -619,7 +619,6 @@ impl Dynamic {
|
||||
|
||||
Self(Union::Variant(Box::new(boxed)))
|
||||
}
|
||||
|
||||
/// Turn the `Dynamic` value into a shared `Dynamic` value backed by an `Rc<RefCell<Dynamic>>`
|
||||
/// or `Arc<RwLock<Dynamic>>` depending on the `sync` feature.
|
||||
///
|
||||
@ -644,7 +643,6 @@ impl Dynamic {
|
||||
#[cfg(feature = "no_closure")]
|
||||
panic!("converting into a shared value is not supported under 'no_closure'");
|
||||
}
|
||||
|
||||
/// Convert the `Dynamic` value into specific type.
|
||||
///
|
||||
/// Casting to a `Dynamic` just returns as is, but if it contains a shared value,
|
||||
@ -775,7 +773,6 @@ impl Dynamic {
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert the `Dynamic` value into a specific type.
|
||||
///
|
||||
/// Casting to a `Dynamic` just returns as is, but if it contains a shared value,
|
||||
@ -819,7 +816,6 @@ impl Dynamic {
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/// Flatten the `Dynamic` and clone it.
|
||||
///
|
||||
/// If the `Dynamic` is not a shared value, it returns a cloned copy.
|
||||
@ -839,7 +835,6 @@ impl Dynamic {
|
||||
_ => self.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Flatten the `Dynamic`.
|
||||
///
|
||||
/// If the `Dynamic` is not a shared value, it returns itself.
|
||||
@ -867,7 +862,6 @@ impl Dynamic {
|
||||
_ => self,
|
||||
}
|
||||
}
|
||||
|
||||
/// Is the `Dynamic` a shared value that is locked?
|
||||
///
|
||||
/// ## Note
|
||||
@ -889,7 +883,6 @@ impl Dynamic {
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a reference of a specific type to the `Dynamic`.
|
||||
/// Casting to `Dynamic` just returns a reference to it.
|
||||
///
|
||||
@ -922,7 +915,6 @@ impl Dynamic {
|
||||
.map(|r| DynamicReadLock(DynamicReadLockInner::Reference(r))),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a mutable reference of a specific type to the `Dynamic`.
|
||||
/// Casting to `Dynamic` just returns a mutable reference to it.
|
||||
///
|
||||
@ -955,7 +947,6 @@ impl Dynamic {
|
||||
.map(|r| DynamicWriteLock(DynamicWriteLockInner::Reference(r))),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a reference of a specific type to the `Dynamic`.
|
||||
/// Casting to `Dynamic` just returns a reference to it.
|
||||
///
|
||||
@ -1045,7 +1036,6 @@ impl Dynamic {
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a mutable reference of a specific type to the `Dynamic`.
|
||||
/// Casting to `Dynamic` just returns a mutable reference to it.
|
||||
///
|
||||
@ -1129,7 +1119,6 @@ impl Dynamic {
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Cast the `Dynamic` as the system integer type `INT` and return it.
|
||||
/// Returns the name of the actual type if the cast fails.
|
||||
#[inline(always)]
|
||||
@ -1141,7 +1130,6 @@ impl Dynamic {
|
||||
_ => Err(self.type_name()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Cast the `Dynamic` as the system floating-point type `FLOAT` and return it.
|
||||
/// Returns the name of the actual type if the cast fails.
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
@ -1154,7 +1142,6 @@ impl Dynamic {
|
||||
_ => Err(self.type_name()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Cast the `Dynamic` as a `bool` and return it.
|
||||
/// Returns the name of the actual type if the cast fails.
|
||||
#[inline(always)]
|
||||
@ -1166,7 +1153,6 @@ impl Dynamic {
|
||||
_ => Err(self.type_name()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Cast the `Dynamic` as a `char` and return it.
|
||||
/// Returns the name of the actual type if the cast fails.
|
||||
#[inline(always)]
|
||||
@ -1178,7 +1164,6 @@ impl Dynamic {
|
||||
_ => Err(self.type_name()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Cast the `Dynamic` as a string and return the string slice.
|
||||
/// Returns the name of the actual type if the cast fails.
|
||||
///
|
||||
@ -1191,7 +1176,6 @@ impl Dynamic {
|
||||
_ => Err(self.type_name()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert the `Dynamic` into `String` and return it.
|
||||
/// If there are other references to the same string, a cloned copy is returned.
|
||||
/// Returns the name of the actual type if the cast fails.
|
||||
@ -1200,7 +1184,6 @@ impl Dynamic {
|
||||
self.take_immutable_string()
|
||||
.map(ImmutableString::into_owned)
|
||||
}
|
||||
|
||||
/// Convert the `Dynamic` into `ImmutableString` and return it.
|
||||
/// Returns the name of the actual type if the cast fails.
|
||||
#[inline]
|
||||
|
@ -2034,8 +2034,8 @@ impl Engine {
|
||||
Stmt::Break(pos) => EvalAltResult::LoopBreak(true, *pos).into(),
|
||||
|
||||
// Try/Catch statement
|
||||
Stmt::TryCatch(x) => {
|
||||
let (try_body, var_def, catch_body, _) = x.as_ref();
|
||||
Stmt::TryCatch(x, _, _) => {
|
||||
let (try_body, var_def, catch_body) = x.as_ref();
|
||||
|
||||
let result = self
|
||||
.eval_stmt(scope, mods, state, lib, this_ptr, try_body, level)
|
||||
|
@ -118,7 +118,6 @@ impl<'a> ArgBackup<'a> {
|
||||
mem::transmute(&mut self.value_copy)
|
||||
}));
|
||||
}
|
||||
|
||||
/// This function restores the first argument that was replaced by `change_first_arg_to_copy`.
|
||||
///
|
||||
/// # Safety
|
||||
@ -541,17 +540,21 @@ impl Engine {
|
||||
// Move captured variables into scope
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
if let Some(captured) = _capture_scope {
|
||||
if let Some(ref externals) = func.externals {
|
||||
captured
|
||||
.into_iter()
|
||||
.filter(|(name, _, _, _)| func.externals.contains(name.as_ref()))
|
||||
.filter(|(name, _, _, _)| externals.contains(name.as_ref()))
|
||||
.for_each(|(name, typ, value, _)| {
|
||||
// Consume the scope values.
|
||||
match typ {
|
||||
ScopeEntryType::Normal => scope.push(name, value),
|
||||
ScopeEntryType::Constant => scope.push_constant(name, value),
|
||||
ScopeEntryType::Constant => {
|
||||
scope.push_constant(name, value)
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let result = if _is_method {
|
||||
// Method call of script function - map first argument to `this`
|
||||
|
@ -387,7 +387,7 @@ fn optimize_stmt(stmt: Stmt, state: &mut State, preserve_result: bool) -> Stmt {
|
||||
}
|
||||
}
|
||||
// try { block } catch ( var ) { block }
|
||||
Stmt::TryCatch(x) if x.0.is_pure() => {
|
||||
Stmt::TryCatch(x, _, _) if x.0.is_pure() => {
|
||||
// If try block is pure, there will never be any exceptions
|
||||
state.set_dirty();
|
||||
let pos = x.0.position();
|
||||
@ -399,14 +399,17 @@ fn optimize_stmt(stmt: Stmt, state: &mut State, preserve_result: bool) -> Stmt {
|
||||
Stmt::Block(statements, pos)
|
||||
}
|
||||
// try { block } catch ( var ) { block }
|
||||
Stmt::TryCatch(x) => {
|
||||
let (try_block, var_name, catch_block, pos) = *x;
|
||||
Stmt::TryCatch(Box::new((
|
||||
Stmt::TryCatch(x, try_pos, catch_pos) => {
|
||||
let (try_block, var_name, catch_block) = *x;
|
||||
Stmt::TryCatch(
|
||||
Box::new((
|
||||
optimize_stmt(try_block, state, false),
|
||||
var_name,
|
||||
optimize_stmt(catch_block, state, false),
|
||||
pos,
|
||||
)))
|
||||
)),
|
||||
try_pos,
|
||||
catch_pos,
|
||||
)
|
||||
}
|
||||
// {}
|
||||
Stmt::Expr(Expr::Stmt(x, pos)) if x.is_empty() => {
|
||||
|
@ -32,7 +32,7 @@ use crate::{
|
||||
use crate::stdlib::{
|
||||
borrow::Cow,
|
||||
boxed::Box,
|
||||
collections::HashMap,
|
||||
collections::{HashMap, HashSet},
|
||||
format,
|
||||
hash::Hash,
|
||||
iter::empty,
|
||||
@ -2376,12 +2376,11 @@ fn parse_try_catch(
|
||||
// try { body } catch ( var ) { catch_block }
|
||||
let catch_body = parse_block(input, state, lib, settings.level_up())?;
|
||||
|
||||
Ok(Stmt::TryCatch(Box::new((
|
||||
body,
|
||||
var_def,
|
||||
catch_body,
|
||||
(token_pos, catch_pos),
|
||||
))))
|
||||
Ok(Stmt::TryCatch(
|
||||
Box::new((body, var_def, catch_body)),
|
||||
token_pos,
|
||||
catch_pos,
|
||||
))
|
||||
}
|
||||
|
||||
/// Parse a function definition.
|
||||
@ -2470,7 +2469,7 @@ fn parse_fn(
|
||||
let params: StaticVec<_> = params.into_iter().map(|(p, _)| p).collect();
|
||||
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
let externals = state
|
||||
let externals: HashSet<_> = state
|
||||
.externals
|
||||
.iter()
|
||||
.map(|(name, _)| name)
|
||||
@ -2483,7 +2482,11 @@ fn parse_fn(
|
||||
access,
|
||||
params,
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
externals,
|
||||
externals: if externals.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(Box::new(externals))
|
||||
},
|
||||
body,
|
||||
lib: None,
|
||||
})
|
||||
|
27
src/scope.rs
27
src/scope.rs
@ -70,8 +70,8 @@ pub struct Scope<'a> {
|
||||
values: Vec<Dynamic>,
|
||||
/// Type of the entry.
|
||||
types: Vec<EntryType>,
|
||||
/// (Name, alias) of the entry.
|
||||
names: Vec<(Cow<'a, str>, Option<String>)>,
|
||||
/// (Name, alias) of the entry. The alias is Boxed because it occurs rarely.
|
||||
names: Vec<(Cow<'a, str>, Option<Box<String>>)>,
|
||||
}
|
||||
|
||||
impl<'a> Scope<'a> {
|
||||
@ -91,7 +91,6 @@ impl<'a> Scope<'a> {
|
||||
pub fn new() -> Self {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
/// Empty the Scope.
|
||||
///
|
||||
/// # Example
|
||||
@ -118,7 +117,6 @@ impl<'a> Scope<'a> {
|
||||
self.values.clear();
|
||||
self
|
||||
}
|
||||
|
||||
/// Get the number of entries inside the Scope.
|
||||
///
|
||||
/// # Example
|
||||
@ -136,7 +134,6 @@ impl<'a> Scope<'a> {
|
||||
pub fn len(&self) -> usize {
|
||||
self.values.len()
|
||||
}
|
||||
|
||||
/// Is the Scope empty?
|
||||
///
|
||||
/// # Example
|
||||
@ -154,7 +151,6 @@ impl<'a> Scope<'a> {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.values.len() == 0
|
||||
}
|
||||
|
||||
/// Add (push) a new entry to the Scope.
|
||||
///
|
||||
/// # Example
|
||||
@ -175,7 +171,6 @@ impl<'a> Scope<'a> {
|
||||
) -> &mut Self {
|
||||
self.push_dynamic_value(name, EntryType::Normal, Dynamic::from(value))
|
||||
}
|
||||
|
||||
/// Add (push) a new `Dynamic` entry to the Scope.
|
||||
///
|
||||
/// # Example
|
||||
@ -192,7 +187,6 @@ impl<'a> Scope<'a> {
|
||||
pub fn push_dynamic(&mut self, name: impl Into<Cow<'a, str>>, value: Dynamic) -> &mut Self {
|
||||
self.push_dynamic_value(name, EntryType::Normal, value)
|
||||
}
|
||||
|
||||
/// Add (push) a new constant to the Scope.
|
||||
///
|
||||
/// Constants are immutable and cannot be assigned to. Their values never change.
|
||||
@ -219,7 +213,6 @@ impl<'a> Scope<'a> {
|
||||
) -> &mut Self {
|
||||
self.push_dynamic_value(name, EntryType::Constant, Dynamic::from(value))
|
||||
}
|
||||
|
||||
/// Add (push) a new constant with a `Dynamic` value to the Scope.
|
||||
///
|
||||
/// Constants are immutable and cannot be assigned to. Their values never change.
|
||||
@ -247,7 +240,6 @@ impl<'a> Scope<'a> {
|
||||
) -> &mut Self {
|
||||
self.push_dynamic_value(name, EntryType::Constant, value)
|
||||
}
|
||||
|
||||
/// Add (push) a new entry with a `Dynamic` value to the Scope.
|
||||
#[inline]
|
||||
pub(crate) fn push_dynamic_value(
|
||||
@ -261,7 +253,6 @@ impl<'a> Scope<'a> {
|
||||
self.values.push(value.into());
|
||||
self
|
||||
}
|
||||
|
||||
/// Truncate (rewind) the Scope to a previous size.
|
||||
///
|
||||
/// # Example
|
||||
@ -295,7 +286,6 @@ impl<'a> Scope<'a> {
|
||||
self.values.truncate(size);
|
||||
self
|
||||
}
|
||||
|
||||
/// Does the scope contain the entry?
|
||||
///
|
||||
/// # Example
|
||||
@ -316,7 +306,6 @@ impl<'a> Scope<'a> {
|
||||
.rev() // Always search a Scope in reverse order
|
||||
.any(|(key, _)| name == key.as_ref())
|
||||
}
|
||||
|
||||
/// Find an entry in the Scope, starting from the last.
|
||||
#[inline(always)]
|
||||
pub(crate) fn get_index(&self, name: &str) -> Option<(usize, EntryType)> {
|
||||
@ -332,7 +321,6 @@ impl<'a> Scope<'a> {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Get the value of an entry in the Scope, starting from the last.
|
||||
///
|
||||
/// # Example
|
||||
@ -354,7 +342,6 @@ impl<'a> Scope<'a> {
|
||||
.find(|(_, (key, _))| name == key.as_ref())
|
||||
.and_then(|(index, _)| self.values[index].flatten_clone().try_cast())
|
||||
}
|
||||
|
||||
/// Update the value of the named entry.
|
||||
/// Search starts backwards from the last, and only the first entry matching the specified name is updated.
|
||||
/// If no entry matching the specified name is found, a new one is added.
|
||||
@ -389,7 +376,6 @@ impl<'a> Scope<'a> {
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Get a mutable reference to an entry in the Scope.
|
||||
#[inline(always)]
|
||||
pub(crate) fn get_mut(&mut self, index: usize) -> (&mut Dynamic, EntryType) {
|
||||
@ -398,16 +384,14 @@ impl<'a> Scope<'a> {
|
||||
self.types[index],
|
||||
)
|
||||
}
|
||||
|
||||
/// Update the access type of an entry in the Scope.
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
#[inline(always)]
|
||||
pub(crate) fn set_entry_alias(&mut self, index: usize, alias: String) -> &mut Self {
|
||||
let entry = self.names.get_mut(index).expect("invalid index in Scope");
|
||||
entry.1 = Some(alias);
|
||||
entry.1 = Some(Box::new(alias));
|
||||
self
|
||||
}
|
||||
|
||||
/// Clone the Scope, keeping only the last instances of each variable name.
|
||||
/// Shadowed variables are omitted in the copy.
|
||||
#[inline]
|
||||
@ -428,7 +412,6 @@ impl<'a> Scope<'a> {
|
||||
|
||||
entries
|
||||
}
|
||||
|
||||
/// Get an iterator to entries in the Scope.
|
||||
#[inline(always)]
|
||||
pub(crate) fn into_iter(
|
||||
@ -437,9 +420,8 @@ impl<'a> Scope<'a> {
|
||||
self.names
|
||||
.into_iter()
|
||||
.zip(self.types.into_iter().zip(self.values.into_iter()))
|
||||
.map(|((name, alias), (typ, value))| (name, typ, value, alias))
|
||||
.map(|((name, alias), (typ, value))| (name, typ, value, alias.map(|v| *v)))
|
||||
}
|
||||
|
||||
/// Get an iterator to entries in the Scope.
|
||||
/// Shared values are flatten-cloned.
|
||||
///
|
||||
@ -470,7 +452,6 @@ impl<'a> Scope<'a> {
|
||||
self.iter_raw()
|
||||
.map(|(name, constant, value)| (name, constant, value.flatten_clone()))
|
||||
}
|
||||
|
||||
/// Get an iterator to entries in the Scope.
|
||||
/// Shared values are not expanded.
|
||||
#[inline(always)]
|
||||
|
@ -85,9 +85,14 @@ impl EvalContext<'_, '_, '_, '_, '_, '_, '_, '_, '_> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Definition of a custom syntax definition.
|
||||
pub struct CustomSyntax {
|
||||
/// A parsing function to return the next keyword in a custom syntax based on the
|
||||
/// keywords parsed so far.
|
||||
pub parse: Box<FnCustomSyntaxParse>,
|
||||
/// Custom syntax implementation function.
|
||||
pub func: Shared<FnCustomSyntaxEval>,
|
||||
/// Delta number of variables in the scope.
|
||||
pub scope_delta: isize,
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user