Remove hashing of the entire script by making Expr and Stmt Hash.
This commit is contained in:
parent
e2a47b2a65
commit
cf9d35166d
176
src/ast.rs
176
src/ast.rs
@ -8,14 +8,13 @@ use crate::stdlib::{
|
||||
boxed::Box,
|
||||
collections::HashMap,
|
||||
fmt,
|
||||
hash::Hash,
|
||||
hash::{Hash, Hasher},
|
||||
num::{NonZeroU64, NonZeroUsize},
|
||||
ops::{Add, AddAssign},
|
||||
ops::{Add, AddAssign, Deref, DerefMut},
|
||||
string::String,
|
||||
vec,
|
||||
vec::Vec,
|
||||
};
|
||||
use crate::syntax::FnCustomSyntaxEval;
|
||||
use crate::token::Token;
|
||||
use crate::utils::StraightHasherBuilder;
|
||||
use crate::{
|
||||
@ -492,11 +491,7 @@ impl AST {
|
||||
(true, true) => vec![],
|
||||
};
|
||||
|
||||
let source = if other.source.is_some() {
|
||||
other.source.clone()
|
||||
} else {
|
||||
self.source.clone()
|
||||
};
|
||||
let source = other.source.clone().or_else(|| self.source.clone());
|
||||
|
||||
let mut functions = functions.as_ref().clone();
|
||||
functions.merge_filtered(&other.functions, &mut filter);
|
||||
@ -696,24 +691,68 @@ pub enum ReturnType {
|
||||
Exception,
|
||||
}
|
||||
|
||||
/// A type that wraps a [`HashMap`]`<u64, Stmt>` for the `switch` statement and implements [`Hash`].
|
||||
#[derive(Clone)]
|
||||
pub struct SwitchHashWrapper(HashMap<u64, Stmt, StraightHasherBuilder>);
|
||||
|
||||
impl From<HashMap<u64, Stmt, StraightHasherBuilder>> for SwitchHashWrapper {
|
||||
fn from(value: HashMap<u64, Stmt, StraightHasherBuilder>) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
impl AsRef<HashMap<u64, Stmt, StraightHasherBuilder>> for SwitchHashWrapper {
|
||||
fn as_ref(&self) -> &HashMap<u64, Stmt, StraightHasherBuilder> {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
impl AsMut<HashMap<u64, Stmt, StraightHasherBuilder>> for SwitchHashWrapper {
|
||||
fn as_mut(&mut self) -> &mut HashMap<u64, Stmt, StraightHasherBuilder> {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
impl Deref for SwitchHashWrapper {
|
||||
type Target = HashMap<u64, Stmt, StraightHasherBuilder>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
impl DerefMut for SwitchHashWrapper {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
impl fmt::Debug for SwitchHashWrapper {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
impl Hash for SwitchHashWrapper {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
let mut keys: Vec<_> = self.0.keys().collect();
|
||||
keys.sort();
|
||||
|
||||
keys.into_iter().for_each(|key| {
|
||||
key.hash(state);
|
||||
self.0.get(&key).unwrap().hash(state);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// _(INTERNALS)_ A statement.
|
||||
/// Exported under the `internals` feature only.
|
||||
///
|
||||
/// # WARNING
|
||||
///
|
||||
/// This type is volatile and may change.
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Hash)]
|
||||
pub enum Stmt {
|
||||
/// No-op.
|
||||
Noop(Position),
|
||||
/// `if` expr `{` stmt `}` `else` `{` stmt `}`
|
||||
If(Expr, Box<(Stmt, Option<Stmt>)>, Position),
|
||||
/// `switch` expr `{` literal or _ `=>` stmt `,` ... `}`
|
||||
Switch(
|
||||
Expr,
|
||||
Box<(HashMap<u64, Stmt, StraightHasherBuilder>, Option<Stmt>)>,
|
||||
Position,
|
||||
),
|
||||
Switch(Expr, Box<(SwitchHashWrapper, Option<Stmt>)>, Position),
|
||||
/// `while` expr `{` stmt `}`
|
||||
While(Expr, Box<Stmt>, Position),
|
||||
/// `do` `{` stmt `}` `while`|`until` expr
|
||||
@ -899,10 +938,8 @@ impl Stmt {
|
||||
/// # WARNING
|
||||
///
|
||||
/// This type is volatile and may change.
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Hash)]
|
||||
pub struct CustomExpr {
|
||||
/// Implementation function.
|
||||
pub func: Shared<FnCustomSyntaxEval>,
|
||||
/// List of keywords.
|
||||
pub keywords: StaticVec<Expr>,
|
||||
/// List of tokens actually parsed.
|
||||
@ -926,7 +963,7 @@ impl fmt::Debug for CustomExpr {
|
||||
/// # WARNING
|
||||
///
|
||||
/// This type is volatile and may change.
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Hash)]
|
||||
pub struct BinaryExpr {
|
||||
/// LHS expression.
|
||||
pub lhs: Expr,
|
||||
@ -940,7 +977,7 @@ pub struct BinaryExpr {
|
||||
/// # WARNING
|
||||
///
|
||||
/// This type is volatile and may change.
|
||||
#[derive(Debug, Clone, Default)]
|
||||
#[derive(Debug, Clone, Default, Hash)]
|
||||
pub struct FnCallExpr {
|
||||
/// Pre-calculated hash for a script-defined function of the same name and number of parameters.
|
||||
/// None if native Rust only.
|
||||
@ -959,13 +996,83 @@ pub struct FnCallExpr {
|
||||
pub args: StaticVec<Expr>,
|
||||
}
|
||||
|
||||
/// A type that wraps a [`FLOAT`] and implements [`Hash`].
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct FloatWrapper(FLOAT);
|
||||
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
impl Hash for FloatWrapper {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.0.to_le_bytes().hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
impl AsRef<FLOAT> for FloatWrapper {
|
||||
fn as_ref(&self) -> &FLOAT {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
impl AsMut<FLOAT> for FloatWrapper {
|
||||
fn as_mut(&mut self) -> &mut FLOAT {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
impl Deref for FloatWrapper {
|
||||
type Target = FLOAT;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
impl DerefMut for FloatWrapper {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
impl fmt::Debug for FloatWrapper {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
impl fmt::Display for FloatWrapper {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
impl From<FLOAT> for FloatWrapper {
|
||||
fn from(value: FLOAT) -> Self {
|
||||
Self::new(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
impl FloatWrapper {
|
||||
pub const fn new(value: FLOAT) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
/// _(INTERNALS)_ An expression sub-tree.
|
||||
/// Exported under the `internals` feature only.
|
||||
///
|
||||
/// # WARNING
|
||||
///
|
||||
/// This type is volatile and may change.
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Hash)]
|
||||
pub enum Expr {
|
||||
/// Dynamic constant.
|
||||
/// Used to hold either an [`Array`] or [`Map`] literal for quick cloning.
|
||||
@ -977,7 +1084,7 @@ pub enum Expr {
|
||||
IntegerConstant(INT, Position),
|
||||
/// Floating-point constant.
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
FloatConstant(FLOAT, Position),
|
||||
FloatConstant(FloatWrapper, Position),
|
||||
/// Character constant.
|
||||
CharConstant(char, Position),
|
||||
/// [String][ImmutableString] constant.
|
||||
@ -1250,19 +1357,20 @@ mod tests {
|
||||
/// 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;
|
||||
use crate::stdlib::mem::size_of;
|
||||
use crate::*;
|
||||
|
||||
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::FnPtr>(), 32);
|
||||
assert_eq!(size_of::<crate::Scope>(), 48);
|
||||
assert_eq!(size_of::<crate::LexError>(), 56);
|
||||
assert_eq!(size_of::<crate::ParseError>(), 16);
|
||||
assert_eq!(size_of::<crate::EvalAltResult>(), 72);
|
||||
assert_eq!(size_of::<Dynamic>(), 16);
|
||||
assert_eq!(size_of::<Option<Dynamic>>(), 16);
|
||||
assert_eq!(size_of::<Position>(), 4);
|
||||
assert_eq!(size_of::<ast::Expr>(), 16);
|
||||
assert_eq!(size_of::<Option<ast::Expr>>(), 16);
|
||||
assert_eq!(size_of::<ast::Stmt>(), 32);
|
||||
assert_eq!(size_of::<Option<ast::Stmt>>(), 32);
|
||||
assert_eq!(size_of::<FnPtr>(), 32);
|
||||
assert_eq!(size_of::<Scope>(), 48);
|
||||
assert_eq!(size_of::<LexError>(), 56);
|
||||
assert_eq!(size_of::<ParseError>(), 16);
|
||||
assert_eq!(size_of::<EvalAltResult>(), 72);
|
||||
}
|
||||
}
|
||||
|
@ -7,14 +7,13 @@ use crate::stdlib::{
|
||||
boxed::Box,
|
||||
fmt,
|
||||
hash::{Hash, Hasher},
|
||||
mem,
|
||||
ops::{Deref, DerefMut},
|
||||
string::String,
|
||||
};
|
||||
use crate::{FnPtr, ImmutableString, INT};
|
||||
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
use crate::FLOAT;
|
||||
use crate::{ast::FloatWrapper, FLOAT};
|
||||
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
use crate::Array;
|
||||
@ -155,7 +154,7 @@ pub enum Union {
|
||||
Char(char, AccessMode),
|
||||
Int(INT, AccessMode),
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
Float(FLOAT, AccessMode),
|
||||
Float(FloatWrapper, AccessMode),
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
Array(Box<Array>, AccessMode),
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
@ -362,8 +361,6 @@ impl Dynamic {
|
||||
|
||||
impl Hash for Dynamic {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
mem::discriminant(self).hash(state);
|
||||
|
||||
match &self.0 {
|
||||
Union::Unit(_, _) => ().hash(state),
|
||||
Union::Bool(value, _) => value.hash(state),
|
||||
@ -371,7 +368,7 @@ impl Hash for Dynamic {
|
||||
Union::Char(ch, _) => ch.hash(state),
|
||||
Union::Int(i, _) => i.hash(state),
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
Union::Float(f, _) => f.to_le_bytes().hash(state),
|
||||
Union::Float(f, _) => f.hash(state),
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
Union::Array(a, _) => (**a).hash(state),
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
@ -559,13 +556,16 @@ impl Dynamic {
|
||||
pub const NEGATIVE_ONE: Dynamic = Self(Union::Int(-1, AccessMode::ReadWrite));
|
||||
/// A [`Dynamic`] containing the floating-point zero.
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
pub const FLOAT_ZERO: Dynamic = Self(Union::Float(0.0, AccessMode::ReadWrite));
|
||||
pub const FLOAT_ZERO: Dynamic =
|
||||
Self(Union::Float(FloatWrapper::new(0.0), AccessMode::ReadWrite));
|
||||
/// A [`Dynamic`] containing the floating-point one.
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
pub const FLOAT_ONE: Dynamic = Self(Union::Float(1.0, AccessMode::ReadWrite));
|
||||
pub const FLOAT_ONE: Dynamic =
|
||||
Self(Union::Float(FloatWrapper::new(1.0), AccessMode::ReadWrite));
|
||||
/// A [`Dynamic`] containing the floating-point negative one.
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
pub const FLOAT_NEGATIVE_ONE: Dynamic = Self(Union::Float(-1.0, AccessMode::ReadWrite));
|
||||
pub const FLOAT_NEGATIVE_ONE: Dynamic =
|
||||
Self(Union::Float(FloatWrapper::new(-1.0), AccessMode::ReadWrite));
|
||||
|
||||
/// Get the [`AccessMode`] for this [`Dynamic`].
|
||||
pub(crate) fn access_mode(&self) -> AccessMode {
|
||||
@ -836,7 +836,7 @@ impl Dynamic {
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
if TypeId::of::<T>() == TypeId::of::<FLOAT>() {
|
||||
return match self.0 {
|
||||
Union::Float(value, _) => unsafe_try_cast(value),
|
||||
Union::Float(value, _) => unsafe_try_cast(*value),
|
||||
_ => None,
|
||||
};
|
||||
}
|
||||
@ -1105,7 +1105,7 @@ impl Dynamic {
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
if TypeId::of::<T>() == TypeId::of::<FLOAT>() {
|
||||
return match &self.0 {
|
||||
Union::Float(value, _) => <dyn Any>::downcast_ref::<T>(value),
|
||||
Union::Float(value, _) => <dyn Any>::downcast_ref::<T>(value.as_ref()),
|
||||
_ => None,
|
||||
};
|
||||
}
|
||||
@ -1194,7 +1194,7 @@ impl Dynamic {
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
if TypeId::of::<T>() == TypeId::of::<FLOAT>() {
|
||||
return match &mut self.0 {
|
||||
Union::Float(value, _) => <dyn Any>::downcast_mut::<T>(value),
|
||||
Union::Float(value, _) => <dyn Any>::downcast_mut::<T>(value.as_mut()),
|
||||
_ => None,
|
||||
};
|
||||
}
|
||||
@ -1277,7 +1277,7 @@ impl Dynamic {
|
||||
#[inline(always)]
|
||||
pub fn as_float(&self) -> Result<FLOAT, &'static str> {
|
||||
match self.0 {
|
||||
Union::Float(n, _) => Ok(n),
|
||||
Union::Float(n, _) => Ok(*n),
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
Union::Shared(_, _) => self.read_lock().map(|v| *v).ok_or_else(|| self.type_name()),
|
||||
_ => Err(self.type_name()),
|
||||
@ -1380,6 +1380,13 @@ impl From<INT> for Dynamic {
|
||||
impl From<FLOAT> for Dynamic {
|
||||
#[inline(always)]
|
||||
fn from(value: FLOAT) -> Self {
|
||||
Self(Union::Float(value.into(), AccessMode::ReadWrite))
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
impl From<FloatWrapper> for Dynamic {
|
||||
#[inline(always)]
|
||||
fn from(value: FloatWrapper) -> Self {
|
||||
Self(Union::Float(value, AccessMode::ReadWrite))
|
||||
}
|
||||
}
|
||||
|
@ -1923,6 +1923,10 @@ impl Engine {
|
||||
.iter()
|
||||
.map(Into::into)
|
||||
.collect::<StaticVec<_>>();
|
||||
let custom_def = self
|
||||
.custom_syntax
|
||||
.get(custom.tokens.first().unwrap())
|
||||
.unwrap();
|
||||
let mut context = EvalContext {
|
||||
engine: self,
|
||||
scope,
|
||||
@ -1932,7 +1936,7 @@ impl Engine {
|
||||
this_ptr,
|
||||
level,
|
||||
};
|
||||
(custom.func)(&mut context, &expressions)
|
||||
(custom_def.func)(&mut context, &expressions)
|
||||
}
|
||||
|
||||
_ => unreachable!("expression cannot be evaluated: {:?}", expr),
|
||||
@ -2072,11 +2076,7 @@ impl Engine {
|
||||
let args = &mut [lhs_ptr_inner, &mut rhs_val];
|
||||
|
||||
// Overriding exact implementation
|
||||
let source = if source.is_none() {
|
||||
state.source.as_ref()
|
||||
} else {
|
||||
source
|
||||
};
|
||||
let source = source.or_else(|| state.source.as_ref());
|
||||
if func.is_plugin_fn() {
|
||||
func.get_plugin_fn()
|
||||
.call((self, source, &*mods, lib).into(), args)?;
|
||||
@ -2130,14 +2130,13 @@ impl Engine {
|
||||
&mut rhs_val,
|
||||
];
|
||||
|
||||
let result = self
|
||||
.exec_fn_call(
|
||||
Some(
|
||||
self.exec_fn_call(
|
||||
mods, state, lib, op, None, args, false, false, false, *op_pos, None,
|
||||
None, level,
|
||||
)
|
||||
.map(|(v, _)| v)?;
|
||||
|
||||
Some((result, rhs_expr.position()))
|
||||
.map(|(v, _)| (v, rhs_expr.position()))?,
|
||||
)
|
||||
};
|
||||
|
||||
// Must be either `var[index] op= val` or `var.prop op= val`
|
||||
|
@ -8,11 +8,9 @@ use crate::stdlib::{
|
||||
any::{type_name, TypeId},
|
||||
boxed::Box,
|
||||
format,
|
||||
hash::{Hash, Hasher},
|
||||
string::String,
|
||||
vec::Vec,
|
||||
};
|
||||
use crate::utils::get_hasher;
|
||||
use crate::{
|
||||
scope::Scope, Dynamic, Engine, EvalAltResult, FnAccess, FnNamespace, Module, NativeCallContext,
|
||||
ParseError, Position, Shared, AST,
|
||||
@ -24,13 +22,6 @@ use crate::Array;
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
use crate::Map;
|
||||
|
||||
/// Calculate a unique hash for a script.
|
||||
fn calc_hash_for_scripts<'a>(scripts: impl IntoIterator<Item = &'a &'a str>) -> u64 {
|
||||
let s = &mut get_hasher();
|
||||
scripts.into_iter().for_each(|&script| script.hash(s));
|
||||
s.finish()
|
||||
}
|
||||
|
||||
/// Engine public API
|
||||
impl Engine {
|
||||
/// Register a function of the [`Engine`].
|
||||
@ -960,9 +951,8 @@ impl Engine {
|
||||
scripts: &[&str],
|
||||
optimization_level: OptimizationLevel,
|
||||
) -> Result<AST, ParseError> {
|
||||
let hash = calc_hash_for_scripts(scripts);
|
||||
let stream = self.lex(scripts);
|
||||
self.parse(hash, &mut stream.peekable(), scope, optimization_level)
|
||||
self.parse(&mut stream.peekable(), scope, optimization_level)
|
||||
}
|
||||
/// Read the contents of a file into a string.
|
||||
#[cfg(not(feature = "no_std"))]
|
||||
@ -1123,8 +1113,6 @@ impl Engine {
|
||||
.into());
|
||||
};
|
||||
|
||||
let hash = calc_hash_for_scripts(&scripts);
|
||||
|
||||
let stream = self.lex_with_map(
|
||||
&scripts,
|
||||
if has_null {
|
||||
@ -1138,12 +1126,8 @@ impl Engine {
|
||||
},
|
||||
);
|
||||
|
||||
let ast = self.parse_global_expr(
|
||||
hash,
|
||||
&mut stream.peekable(),
|
||||
&scope,
|
||||
OptimizationLevel::None,
|
||||
)?;
|
||||
let ast =
|
||||
self.parse_global_expr(&mut stream.peekable(), &scope, OptimizationLevel::None)?;
|
||||
|
||||
// Handle null - map to ()
|
||||
if has_null {
|
||||
@ -1222,11 +1206,10 @@ impl Engine {
|
||||
script: &str,
|
||||
) -> Result<AST, ParseError> {
|
||||
let scripts = [script];
|
||||
let hash = calc_hash_for_scripts(&scripts);
|
||||
let stream = self.lex(&scripts);
|
||||
|
||||
let mut peekable = stream.peekable();
|
||||
self.parse_global_expr(hash, &mut peekable, scope, self.optimization_level)
|
||||
self.parse_global_expr(&mut peekable, scope, self.optimization_level)
|
||||
}
|
||||
/// Evaluate a script file.
|
||||
///
|
||||
@ -1384,12 +1367,10 @@ impl Engine {
|
||||
script: &str,
|
||||
) -> Result<T, Box<EvalAltResult>> {
|
||||
let scripts = [script];
|
||||
let hash = calc_hash_for_scripts(&scripts);
|
||||
let stream = self.lex(&scripts);
|
||||
|
||||
// No need to optimize a lone expression
|
||||
let ast =
|
||||
self.parse_global_expr(hash, &mut stream.peekable(), scope, OptimizationLevel::None)?;
|
||||
let ast = self.parse_global_expr(&mut stream.peekable(), scope, OptimizationLevel::None)?;
|
||||
|
||||
self.eval_ast_with_scope(scope, &ast)
|
||||
}
|
||||
@ -1522,9 +1503,8 @@ impl Engine {
|
||||
script: &str,
|
||||
) -> Result<(), Box<EvalAltResult>> {
|
||||
let scripts = [script];
|
||||
let hash = calc_hash_for_scripts(&scripts);
|
||||
let stream = self.lex(&scripts);
|
||||
let ast = self.parse(hash, &mut stream.peekable(), scope, self.optimization_level)?;
|
||||
let ast = self.parse(&mut stream.peekable(), scope, self.optimization_level)?;
|
||||
self.consume_ast_with_scope(scope, &ast)
|
||||
}
|
||||
/// Evaluate an AST, but throw away the result and only return error (if any).
|
||||
|
@ -183,7 +183,10 @@ pub use token::{get_next_token, parse_string_literal, InputStream, Token, Tokeni
|
||||
|
||||
#[cfg(feature = "internals")]
|
||||
#[deprecated = "this type is volatile and may change"]
|
||||
pub use ast::{BinaryExpr, CustomExpr, Expr, FnCallExpr, Ident, ReturnType, ScriptFnDef, Stmt};
|
||||
pub use ast::{
|
||||
BinaryExpr, CustomExpr, Expr, FloatWrapper, FnCallExpr, Ident, ReturnType, ScriptFnDef, Stmt,
|
||||
SwitchHashWrapper,
|
||||
};
|
||||
|
||||
#[cfg(feature = "internals")]
|
||||
#[deprecated = "this type is volatile and may change"]
|
||||
|
@ -41,8 +41,6 @@ type FunctionsLib = HashMap<NonZeroU64, ScriptFnDef, StraightHasherBuilder>;
|
||||
struct ParseState<'e> {
|
||||
/// Reference to the scripting [`Engine`].
|
||||
engine: &'e Engine,
|
||||
/// Hash that uniquely identifies a script.
|
||||
script_hash: u64,
|
||||
/// Interned strings.
|
||||
strings: HashMap<String, ImmutableString>,
|
||||
/// Encapsulates a local stack with variable names to simulate an actual runtime scope.
|
||||
@ -75,7 +73,6 @@ impl<'e> ParseState<'e> {
|
||||
#[inline(always)]
|
||||
pub fn new(
|
||||
engine: &'e Engine,
|
||||
script_hash: u64,
|
||||
#[cfg(not(feature = "unchecked"))] max_expr_depth: usize,
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
@ -83,7 +80,6 @@ impl<'e> ParseState<'e> {
|
||||
) -> Self {
|
||||
Self {
|
||||
engine,
|
||||
script_hash,
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
max_expr_depth,
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
@ -919,7 +915,7 @@ fn parse_switch(
|
||||
|
||||
Ok(Stmt::Switch(
|
||||
item,
|
||||
Box::new((final_table, def_stmt)),
|
||||
Box::new((final_table.into(), def_stmt)),
|
||||
settings.pos,
|
||||
))
|
||||
}
|
||||
@ -956,7 +952,7 @@ fn parse_primary(
|
||||
},
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
Token::FloatConstant(x) => {
|
||||
let x = *x;
|
||||
let x = (*x).into();
|
||||
input.next().unwrap();
|
||||
Expr::FloatConstant(x, settings.pos)
|
||||
}
|
||||
@ -986,7 +982,6 @@ fn parse_primary(
|
||||
Token::Pipe | Token::Or if settings.allow_anonymous_fn => {
|
||||
let mut new_state = ParseState::new(
|
||||
state.engine,
|
||||
state.script_hash,
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
state.max_function_expr_depth,
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
@ -1284,7 +1279,7 @@ fn parse_unary(
|
||||
.map(|i| Expr::IntegerConstant(i, pos))
|
||||
.or_else(|| {
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
return Some(Expr::FloatConstant(-(num as FLOAT), pos));
|
||||
return Some(Expr::FloatConstant((-(num as FLOAT)).into(), pos));
|
||||
#[cfg(feature = "no_float")]
|
||||
return None;
|
||||
})
|
||||
@ -1292,7 +1287,7 @@ fn parse_unary(
|
||||
|
||||
// Negative float
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
Expr::FloatConstant(x, pos) => Ok(Expr::FloatConstant(-x, pos)),
|
||||
Expr::FloatConstant(x, pos) => Ok(Expr::FloatConstant((-(*x)).into(), pos)),
|
||||
|
||||
// Call negative function
|
||||
expr => {
|
||||
@ -1998,14 +1993,7 @@ fn parse_custom_syntax(
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Expr::Custom(
|
||||
Box::new(CustomExpr {
|
||||
keywords,
|
||||
func: syntax.func.clone(),
|
||||
tokens,
|
||||
}),
|
||||
pos,
|
||||
))
|
||||
Ok(Expr::Custom(Box::new(CustomExpr { keywords, tokens }), pos))
|
||||
}
|
||||
|
||||
/// Parse an expression.
|
||||
@ -2600,7 +2588,6 @@ fn parse_stmt(
|
||||
(Token::Fn, pos) => {
|
||||
let mut new_state = ParseState::new(
|
||||
state.engine,
|
||||
state.script_hash,
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
state.max_function_expr_depth,
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
@ -3009,10 +2996,10 @@ fn parse_anon_fn(
|
||||
params.into_iter().map(|(v, _)| v).collect()
|
||||
};
|
||||
|
||||
// Create unique function name by hashing the script hash plus the position
|
||||
// Create unique function name by hashing the script body plus the parameters.
|
||||
let hasher = &mut get_hasher();
|
||||
state.script_hash.hash(hasher);
|
||||
settings.pos.hash(hasher);
|
||||
params.iter().for_each(|p| p.as_str().hash(hasher));
|
||||
body.hash(hasher);
|
||||
let hash = hasher.finish();
|
||||
|
||||
let fn_name: ImmutableString = format!("{}{:016x}", crate::engine::FN_ANONYMOUS, hash).into();
|
||||
@ -3045,7 +3032,6 @@ fn parse_anon_fn(
|
||||
impl Engine {
|
||||
pub(crate) fn parse_global_expr(
|
||||
&self,
|
||||
script_hash: u64,
|
||||
input: &mut TokenStream,
|
||||
scope: &Scope,
|
||||
optimization_level: OptimizationLevel,
|
||||
@ -3053,7 +3039,6 @@ impl Engine {
|
||||
let mut functions = Default::default();
|
||||
let mut state = ParseState::new(
|
||||
self,
|
||||
script_hash,
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
self.max_expr_depth(),
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
@ -3095,14 +3080,12 @@ impl Engine {
|
||||
/// Parse the global level statements.
|
||||
fn parse_global_level(
|
||||
&self,
|
||||
script_hash: u64,
|
||||
input: &mut TokenStream,
|
||||
) -> Result<(Vec<Stmt>, Vec<ScriptFnDef>), ParseError> {
|
||||
let mut statements = Vec::with_capacity(16);
|
||||
let mut functions = HashMap::with_capacity_and_hasher(16, StraightHasherBuilder);
|
||||
let mut state = ParseState::new(
|
||||
self,
|
||||
script_hash,
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
self.max_expr_depth(),
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
@ -3165,12 +3148,11 @@ impl Engine {
|
||||
#[inline(always)]
|
||||
pub(crate) fn parse(
|
||||
&self,
|
||||
script_hash: u64,
|
||||
input: &mut TokenStream,
|
||||
scope: &Scope,
|
||||
optimization_level: OptimizationLevel,
|
||||
) -> Result<AST, ParseError> {
|
||||
let (statements, lib) = self.parse_global_level(script_hash, input)?;
|
||||
let (statements, lib) = self.parse_global_level(input)?;
|
||||
|
||||
Ok(
|
||||
// Optimize AST
|
||||
|
Loading…
Reference in New Issue
Block a user