Code structure refactor.
This commit is contained in:
parent
cbd7ed2ca7
commit
4e115d2bc2
@ -5,7 +5,9 @@ Rhai Release Notes
|
|||||||
Version 0.19.4
|
Version 0.19.4
|
||||||
==============
|
==============
|
||||||
|
|
||||||
This version adds a low-level API for more flexibility when defining custom syntax.
|
This version basically cleans up the code structure in preparation for a potential `1.0` release in the future.
|
||||||
|
|
||||||
|
This version also adds a low-level API for more flexibility when defining custom syntax.
|
||||||
|
|
||||||
Bug fixes
|
Bug fixes
|
||||||
---------
|
---------
|
||||||
|
804
src/ast.rs
804
src/ast.rs
@ -1,15 +1,124 @@
|
|||||||
//! Module defining the AST (abstract syntax tree).
|
//! Module defining the AST (abstract syntax tree).
|
||||||
|
|
||||||
use crate::fn_native::Shared;
|
use crate::dynamic::{Dynamic, Union};
|
||||||
use crate::module::Module;
|
use crate::fn_native::{FnPtr, Shared};
|
||||||
use crate::parser::{FnAccess, ScriptFnDef, Stmt};
|
use crate::module::{Module, ModuleRef};
|
||||||
|
use crate::syntax::FnCustomSyntaxEval;
|
||||||
|
use crate::token::{Position, Token};
|
||||||
|
use crate::utils::ImmutableString;
|
||||||
|
use crate::StaticVec;
|
||||||
|
use crate::INT;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
use crate::FLOAT;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
use crate::engine::Array;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
use crate::engine::{make_getter, make_setter, Map};
|
||||||
|
|
||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
|
any::TypeId,
|
||||||
|
borrow::Cow,
|
||||||
|
fmt,
|
||||||
|
hash::{Hash, Hasher},
|
||||||
|
num::NonZeroUsize,
|
||||||
ops::{Add, AddAssign},
|
ops::{Add, AddAssign},
|
||||||
|
string::String,
|
||||||
vec,
|
vec,
|
||||||
vec::Vec,
|
vec::Vec,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
use crate::stdlib::ops::Neg;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_closure"))]
|
||||||
|
use crate::stdlib::collections::HashSet;
|
||||||
|
|
||||||
|
/// A type representing the access mode of a scripted function.
|
||||||
|
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
|
||||||
|
pub enum FnAccess {
|
||||||
|
/// Public function.
|
||||||
|
Public,
|
||||||
|
/// Private function.
|
||||||
|
Private,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for FnAccess {
|
||||||
|
#[inline(always)]
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::Private => write!(f, "private"),
|
||||||
|
Self::Public => write!(f, "public"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FnAccess {
|
||||||
|
/// Is this access mode private?
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn is_private(self) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::Public => false,
|
||||||
|
Self::Private => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Is this access mode public?
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn is_public(self) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::Public => true,
|
||||||
|
Self::Private => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// _[INTERNALS]_ A type containing information on a scripted function.
|
||||||
|
/// Exported under the `internals` feature only.
|
||||||
|
///
|
||||||
|
/// ## WARNING
|
||||||
|
///
|
||||||
|
/// This type is volatile and may change.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct ScriptFnDef {
|
||||||
|
/// Function name.
|
||||||
|
pub name: ImmutableString,
|
||||||
|
/// Function access mode.
|
||||||
|
pub access: FnAccess,
|
||||||
|
/// Names of function parameters.
|
||||||
|
pub params: StaticVec<String>,
|
||||||
|
/// Access to external variables.
|
||||||
|
#[cfg(not(feature = "no_closure"))]
|
||||||
|
pub externals: HashSet<String>,
|
||||||
|
/// Function body.
|
||||||
|
pub body: Stmt,
|
||||||
|
/// Position of the function definition.
|
||||||
|
pub pos: Position,
|
||||||
|
/// Encapsulated running environment, if any.
|
||||||
|
pub lib: Option<Shared<Module>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ScriptFnDef {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{}{}({})",
|
||||||
|
if self.access.is_private() {
|
||||||
|
"private "
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
},
|
||||||
|
self.name,
|
||||||
|
self.params
|
||||||
|
.iter()
|
||||||
|
.map(|s| s.as_str())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(",")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Compiled AST (abstract syntax tree) of a Rhai script.
|
/// Compiled AST (abstract syntax tree) of a Rhai script.
|
||||||
///
|
///
|
||||||
/// # Thread Safety
|
/// # Thread Safety
|
||||||
@ -73,6 +182,7 @@ impl AST {
|
|||||||
/// No statements are cloned.
|
/// No statements are cloned.
|
||||||
///
|
///
|
||||||
/// This operation is cheap because functions are shared.
|
/// This operation is cheap because functions are shared.
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn clone_functions_only(&self) -> Self {
|
pub fn clone_functions_only(&self) -> Self {
|
||||||
self.clone_functions_only_filtered(|_, _, _| true)
|
self.clone_functions_only_filtered(|_, _, _| true)
|
||||||
@ -82,6 +192,7 @@ impl AST {
|
|||||||
/// No statements are cloned.
|
/// No statements are cloned.
|
||||||
///
|
///
|
||||||
/// This operation is cheap because functions are shared.
|
/// This operation is cheap because functions are shared.
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn clone_functions_only_filtered(
|
pub fn clone_functions_only_filtered(
|
||||||
&self,
|
&self,
|
||||||
@ -425,3 +536,690 @@ impl AsRef<Module> for AST {
|
|||||||
self.lib()
|
self.lib()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An identifier containing a string name and a position.
|
||||||
|
#[derive(Debug, Clone, Hash)]
|
||||||
|
pub struct Ident {
|
||||||
|
pub name: String,
|
||||||
|
pub pos: Position,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ident {
|
||||||
|
/// Create a new `Identifier`.
|
||||||
|
pub fn new(name: String, pos: Position) -> Self {
|
||||||
|
Self { name, pos }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An identifier containing an immutable name and a position.
|
||||||
|
#[derive(Debug, Clone, Hash)]
|
||||||
|
pub struct IdentX {
|
||||||
|
pub name: ImmutableString,
|
||||||
|
pub pos: Position,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IdentX {
|
||||||
|
/// Create a new `Identifier`.
|
||||||
|
pub fn new(name: impl Into<ImmutableString>, pos: Position) -> Self {
|
||||||
|
Self {
|
||||||
|
name: name.into(),
|
||||||
|
pos,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// _[INTERNALS]_ A type encapsulating the mode of a `return`/`throw` statement.
|
||||||
|
/// Exported under the `internals` feature only.
|
||||||
|
///
|
||||||
|
/// ## WARNING
|
||||||
|
///
|
||||||
|
/// This type is volatile and may change.
|
||||||
|
#[derive(Debug, Eq, PartialEq, Clone, Copy, Hash)]
|
||||||
|
pub enum ReturnType {
|
||||||
|
/// `return` statement.
|
||||||
|
Return,
|
||||||
|
/// `throw` statement.
|
||||||
|
Exception,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// _[INTERNALS]_ A Rhai 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.
|
||||||
|
#[derive(Debug, Clone, Hash)]
|
||||||
|
pub enum Stmt {
|
||||||
|
/// No-op.
|
||||||
|
Noop(Position),
|
||||||
|
/// if expr { stmt } else { stmt }
|
||||||
|
IfThenElse(Expr, Box<(Stmt, Option<Stmt>)>, Position),
|
||||||
|
/// while expr { stmt }
|
||||||
|
While(Expr, Box<Stmt>, Position),
|
||||||
|
/// loop { stmt }
|
||||||
|
Loop(Box<Stmt>, Position),
|
||||||
|
/// for id in expr { stmt }
|
||||||
|
For(Expr, Box<(String, Stmt)>, Position),
|
||||||
|
/// let id = expr
|
||||||
|
Let(Box<Ident>, Option<Expr>, Position),
|
||||||
|
/// const id = expr
|
||||||
|
Const(Box<Ident>, Option<Expr>, Position),
|
||||||
|
/// expr op= expr
|
||||||
|
Assignment(Box<(Expr, Cow<'static, str>, Expr)>, Position),
|
||||||
|
/// { stmt; ... }
|
||||||
|
Block(Vec<Stmt>, Position),
|
||||||
|
/// try { stmt; ... } catch ( var ) { stmt; ... }
|
||||||
|
TryCatch(Box<(Stmt, Option<Ident>, Stmt, (Position, Position))>),
|
||||||
|
/// expr
|
||||||
|
Expr(Expr),
|
||||||
|
/// continue
|
||||||
|
Continue(Position),
|
||||||
|
/// break
|
||||||
|
Break(Position),
|
||||||
|
/// return/throw
|
||||||
|
ReturnWithVal((ReturnType, Position), Option<Expr>, Position),
|
||||||
|
/// import expr as var
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
Import(Expr, Option<Box<IdentX>>, Position),
|
||||||
|
/// export var as var, ...
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
Export(Vec<(Ident, Option<Ident>)>, Position),
|
||||||
|
/// Convert a variable to shared.
|
||||||
|
#[cfg(not(feature = "no_closure"))]
|
||||||
|
Share(Ident),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Stmt {
|
||||||
|
#[inline(always)]
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Noop(Default::default())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Stmt {
|
||||||
|
/// Is this statement `Noop`?
|
||||||
|
pub fn is_noop(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::Noop(_) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the `Position` of this statement.
|
||||||
|
pub fn position(&self) -> Position {
|
||||||
|
match self {
|
||||||
|
Self::Noop(pos)
|
||||||
|
| Self::Continue(pos)
|
||||||
|
| Self::Break(pos)
|
||||||
|
| Self::Block(_, pos)
|
||||||
|
| Self::Assignment(_, pos)
|
||||||
|
| Self::IfThenElse(_, _, pos)
|
||||||
|
| Self::While(_, _, pos)
|
||||||
|
| Self::Loop(_, pos)
|
||||||
|
| Self::For(_, _, pos)
|
||||||
|
| Self::ReturnWithVal((_, pos), _, _) => *pos,
|
||||||
|
|
||||||
|
Self::Let(x, _, _) | Self::Const(x, _, _) => x.pos,
|
||||||
|
Self::TryCatch(x) => (x.3).0,
|
||||||
|
|
||||||
|
Self::Expr(x) => x.position(),
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
Self::Import(_, _, pos) => *pos,
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
Self::Export(_, pos) => *pos,
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_closure"))]
|
||||||
|
Self::Share(Ident { pos, .. }) => *pos,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Override the `Position` of this statement.
|
||||||
|
pub fn set_position(&mut self, new_pos: Position) -> &mut Self {
|
||||||
|
match self {
|
||||||
|
Self::Noop(pos)
|
||||||
|
| Self::Continue(pos)
|
||||||
|
| Self::Break(pos)
|
||||||
|
| Self::Block(_, pos)
|
||||||
|
| Self::Assignment(_, pos)
|
||||||
|
| Self::IfThenElse(_, _, pos)
|
||||||
|
| Self::While(_, _, pos)
|
||||||
|
| Self::Loop(_, pos)
|
||||||
|
| Self::For(_, _, pos)
|
||||||
|
| 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::Expr(x) => {
|
||||||
|
x.set_position(new_pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
Self::Import(_, _, pos) => *pos = new_pos,
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
Self::Export(_, pos) => *pos = new_pos,
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_closure"))]
|
||||||
|
Self::Share(Ident { pos, .. }) => *pos = new_pos,
|
||||||
|
}
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Is this statement self-terminated (i.e. no need for a semicolon terminator)?
|
||||||
|
pub fn is_self_terminated(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::IfThenElse(_, _, _)
|
||||||
|
| Self::While(_, _, _)
|
||||||
|
| Self::Loop(_, _)
|
||||||
|
| Self::For(_, _, _)
|
||||||
|
| Self::Block(_, _)
|
||||||
|
| Self::TryCatch(_) => true,
|
||||||
|
|
||||||
|
// A No-op requires a semicolon in order to know it is an empty statement!
|
||||||
|
Self::Noop(_) => false,
|
||||||
|
|
||||||
|
Self::Let(_, _, _)
|
||||||
|
| Self::Const(_, _, _)
|
||||||
|
| Self::Assignment(_, _)
|
||||||
|
| Self::Expr(_)
|
||||||
|
| Self::Continue(_)
|
||||||
|
| Self::Break(_)
|
||||||
|
| Self::ReturnWithVal(_, _, _) => false,
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
Self::Import(_, _, _) | Self::Export(_, _) => false,
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_closure"))]
|
||||||
|
Self::Share(_) => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Is this statement _pure_?
|
||||||
|
pub fn is_pure(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::Noop(_) => true,
|
||||||
|
Self::Expr(expr) => expr.is_pure(),
|
||||||
|
Self::IfThenElse(condition, x, _) if x.1.is_some() => {
|
||||||
|
condition.is_pure() && x.0.is_pure() && x.1.as_ref().unwrap().is_pure()
|
||||||
|
}
|
||||||
|
Self::IfThenElse(condition, x, _) => condition.is_pure() && x.0.is_pure(),
|
||||||
|
Self::While(condition, block, _) => condition.is_pure() && block.is_pure(),
|
||||||
|
Self::Loop(block, _) => block.is_pure(),
|
||||||
|
Self::For(iterable, x, _) => iterable.is_pure() && x.1.is_pure(),
|
||||||
|
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(),
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
Self::Import(_, _, _) => false,
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
Self::Export(_, _) => false,
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_closure"))]
|
||||||
|
Self::Share(_) => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// _[INTERNALS]_ A type wrapping a custom syntax definition.
|
||||||
|
/// Exported under the `internals` feature only.
|
||||||
|
///
|
||||||
|
/// ## WARNING
|
||||||
|
///
|
||||||
|
/// This type is volatile and may change.
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct CustomExpr {
|
||||||
|
pub(crate) keywords: StaticVec<Expr>,
|
||||||
|
pub(crate) func: Shared<FnCustomSyntaxEval>,
|
||||||
|
pub(crate) pos: Position,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for CustomExpr {
|
||||||
|
#[inline(always)]
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
fmt::Debug::fmt(&self.keywords, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hash for CustomExpr {
|
||||||
|
#[inline(always)]
|
||||||
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
self.keywords.hash(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CustomExpr {
|
||||||
|
/// Get the keywords for this `CustomExpr`.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn keywords(&self) -> &[Expr] {
|
||||||
|
&self.keywords
|
||||||
|
}
|
||||||
|
/// Get the implementation function for this `CustomExpr`.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn func(&self) -> &FnCustomSyntaxEval {
|
||||||
|
self.func.as_ref()
|
||||||
|
}
|
||||||
|
/// Get the position of this `CustomExpr`.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn position(&self) -> Position {
|
||||||
|
self.pos
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// _[INTERNALS]_ A type wrapping a floating-point number.
|
||||||
|
/// Exported under the `internals` feature only.
|
||||||
|
///
|
||||||
|
/// This type is mainly used to provide a standard `Hash` implementation
|
||||||
|
/// to floating-point numbers, allowing `Expr` to derive `Hash` automatically.
|
||||||
|
///
|
||||||
|
/// ## WARNING
|
||||||
|
///
|
||||||
|
/// This type is volatile and may change.
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
#[derive(Debug, PartialEq, PartialOrd, Clone)]
|
||||||
|
pub struct FloatWrapper(pub FLOAT, pub Position);
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
impl Hash for FloatWrapper {
|
||||||
|
#[inline(always)]
|
||||||
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
state.write(&self.0.to_le_bytes());
|
||||||
|
self.1.hash(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
impl Neg for FloatWrapper {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn neg(self) -> Self::Output {
|
||||||
|
Self(-self.0, self.1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
impl From<(INT, Position)> for FloatWrapper {
|
||||||
|
fn from((value, pos): (INT, Position)) -> Self {
|
||||||
|
Self(value as FLOAT, pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A binary expression structure.
|
||||||
|
#[derive(Debug, Clone, Hash)]
|
||||||
|
pub struct BinaryExpr {
|
||||||
|
pub lhs: Expr,
|
||||||
|
pub rhs: Expr,
|
||||||
|
pub pos: Position,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// _[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.
|
||||||
|
#[derive(Debug, Clone, Hash)]
|
||||||
|
pub enum Expr {
|
||||||
|
/// Integer constant.
|
||||||
|
IntegerConstant(Box<(INT, Position)>),
|
||||||
|
/// Floating-point constant.
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
FloatConstant(Box<FloatWrapper>),
|
||||||
|
/// Character constant.
|
||||||
|
CharConstant(Box<(char, Position)>),
|
||||||
|
/// String constant.
|
||||||
|
StringConstant(Box<IdentX>),
|
||||||
|
/// FnPtr constant.
|
||||||
|
FnPointer(Box<IdentX>),
|
||||||
|
/// Variable access - ((variable name, position), optional modules, hash, optional index)
|
||||||
|
Variable(Box<(Ident, Option<Box<ModuleRef>>, u64, Option<NonZeroUsize>)>),
|
||||||
|
/// Property access.
|
||||||
|
Property(Box<((ImmutableString, String, String), Position)>),
|
||||||
|
/// { stmt }
|
||||||
|
Stmt(Box<(Stmt, Position)>),
|
||||||
|
/// Wrapped expression - should not be optimized away.
|
||||||
|
Expr(Box<Expr>),
|
||||||
|
/// func(expr, ... ) - ((function name, native_only, capture, position), optional modules, hash, arguments, optional default value)
|
||||||
|
/// Use `Cow<'static, str>` because a lot of operators (e.g. `==`, `>=`) are implemented as function calls
|
||||||
|
/// and the function names are predictable, so no need to allocate a new `String`.
|
||||||
|
FnCall(
|
||||||
|
Box<(
|
||||||
|
(Cow<'static, str>, bool, bool, Position),
|
||||||
|
Option<Box<ModuleRef>>,
|
||||||
|
u64,
|
||||||
|
StaticVec<Expr>,
|
||||||
|
Option<bool>, // Default value is `bool` in order for `Expr` to be `Hash`.
|
||||||
|
)>,
|
||||||
|
),
|
||||||
|
/// lhs.rhs
|
||||||
|
Dot(Box<BinaryExpr>),
|
||||||
|
/// expr[expr]
|
||||||
|
Index(Box<BinaryExpr>),
|
||||||
|
/// [ expr, ... ]
|
||||||
|
Array(Box<(StaticVec<Expr>, Position)>),
|
||||||
|
/// #{ name:expr, ... }
|
||||||
|
Map(Box<(StaticVec<(IdentX, Expr)>, Position)>),
|
||||||
|
/// lhs in rhs
|
||||||
|
In(Box<BinaryExpr>),
|
||||||
|
/// lhs && rhs
|
||||||
|
And(Box<BinaryExpr>),
|
||||||
|
/// lhs || rhs
|
||||||
|
Or(Box<BinaryExpr>),
|
||||||
|
/// true
|
||||||
|
True(Position),
|
||||||
|
/// false
|
||||||
|
False(Position),
|
||||||
|
/// ()
|
||||||
|
Unit(Position),
|
||||||
|
/// Custom syntax
|
||||||
|
Custom(Box<CustomExpr>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Expr {
|
||||||
|
#[inline(always)]
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Unit(Default::default())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Expr {
|
||||||
|
/// Get the type of an expression.
|
||||||
|
///
|
||||||
|
/// Returns `None` if the expression's result type is not constant.
|
||||||
|
pub fn get_type_id(&self) -> Option<TypeId> {
|
||||||
|
Some(match self {
|
||||||
|
Self::Expr(x) => return x.get_type_id(),
|
||||||
|
|
||||||
|
Self::IntegerConstant(_) => TypeId::of::<INT>(),
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
Self::FloatConstant(_) => TypeId::of::<FLOAT>(),
|
||||||
|
Self::CharConstant(_) => TypeId::of::<char>(),
|
||||||
|
Self::StringConstant(_) => TypeId::of::<ImmutableString>(),
|
||||||
|
Self::FnPointer(_) => TypeId::of::<FnPtr>(),
|
||||||
|
Self::True(_) | Self::False(_) | Self::In(_) | Self::And(_) | Self::Or(_) => {
|
||||||
|
TypeId::of::<bool>()
|
||||||
|
}
|
||||||
|
Self::Unit(_) => TypeId::of::<()>(),
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
Self::Array(_) => TypeId::of::<Array>(),
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
Self::Map(_) => TypeId::of::<Map>(),
|
||||||
|
|
||||||
|
_ => return None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the `Dynamic` value of a constant expression.
|
||||||
|
///
|
||||||
|
/// Returns `None` if the expression is not constant.
|
||||||
|
pub fn get_constant_value(&self) -> Option<Dynamic> {
|
||||||
|
Some(match self {
|
||||||
|
Self::Expr(x) => return x.get_constant_value(),
|
||||||
|
|
||||||
|
Self::IntegerConstant(x) => x.0.into(),
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
Self::FloatConstant(x) => x.0.into(),
|
||||||
|
Self::CharConstant(x) => x.0.into(),
|
||||||
|
Self::StringConstant(x) => x.name.clone().into(),
|
||||||
|
Self::FnPointer(x) => Dynamic(Union::FnPtr(Box::new(FnPtr::new_unchecked(
|
||||||
|
x.name.clone(),
|
||||||
|
Default::default(),
|
||||||
|
)))),
|
||||||
|
Self::True(_) => true.into(),
|
||||||
|
Self::False(_) => false.into(),
|
||||||
|
Self::Unit(_) => ().into(),
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
Self::Array(x) if x.0.iter().all(Self::is_constant) => Dynamic(Union::Array(Box::new(
|
||||||
|
x.0.iter()
|
||||||
|
.map(|v| v.get_constant_value().unwrap())
|
||||||
|
.collect(),
|
||||||
|
))),
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
Self::Map(x) if x.0.iter().all(|(_, v)| v.is_constant()) => {
|
||||||
|
Dynamic(Union::Map(Box::new(
|
||||||
|
x.0.iter()
|
||||||
|
.map(|(k, v)| (k.name.clone(), v.get_constant_value().unwrap()))
|
||||||
|
.collect(),
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => return None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Is the expression a simple variable access?
|
||||||
|
pub(crate) fn get_variable_access(&self, non_qualified: bool) -> Option<&str> {
|
||||||
|
match self {
|
||||||
|
Self::Variable(x) if !non_qualified || x.1.is_none() => Some((x.0).name.as_str()),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the `Position` of the expression.
|
||||||
|
pub fn position(&self) -> Position {
|
||||||
|
match self {
|
||||||
|
Self::Expr(x) => x.position(),
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
Self::FloatConstant(x) => x.1,
|
||||||
|
|
||||||
|
Self::IntegerConstant(x) => x.1,
|
||||||
|
Self::CharConstant(x) => x.1,
|
||||||
|
Self::StringConstant(x) => x.pos,
|
||||||
|
Self::FnPointer(x) => x.pos,
|
||||||
|
Self::Array(x) => x.1,
|
||||||
|
Self::Map(x) => x.1,
|
||||||
|
Self::Property(x) => x.1,
|
||||||
|
Self::Stmt(x) => x.1,
|
||||||
|
Self::Variable(x) => (x.0).pos,
|
||||||
|
Self::FnCall(x) => (x.0).3,
|
||||||
|
|
||||||
|
Self::And(x) | Self::Or(x) | Self::In(x) => x.pos,
|
||||||
|
|
||||||
|
Self::True(pos) | Self::False(pos) | Self::Unit(pos) => *pos,
|
||||||
|
|
||||||
|
Self::Dot(x) | Self::Index(x) => x.lhs.position(),
|
||||||
|
|
||||||
|
Self::Custom(x) => x.pos,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Override the `Position` of the expression.
|
||||||
|
pub fn set_position(&mut self, new_pos: Position) -> &mut Self {
|
||||||
|
match self {
|
||||||
|
Self::Expr(x) => {
|
||||||
|
x.set_position(new_pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
Self::FloatConstant(x) => x.1 = new_pos,
|
||||||
|
|
||||||
|
Self::IntegerConstant(x) => x.1 = new_pos,
|
||||||
|
Self::CharConstant(x) => x.1 = new_pos,
|
||||||
|
Self::StringConstant(x) => x.pos = new_pos,
|
||||||
|
Self::FnPointer(x) => x.pos = new_pos,
|
||||||
|
Self::Array(x) => x.1 = new_pos,
|
||||||
|
Self::Map(x) => x.1 = new_pos,
|
||||||
|
Self::Variable(x) => (x.0).pos = new_pos,
|
||||||
|
Self::Property(x) => x.1 = new_pos,
|
||||||
|
Self::Stmt(x) => x.1 = new_pos,
|
||||||
|
Self::FnCall(x) => (x.0).3 = new_pos,
|
||||||
|
Self::And(x) | Self::Or(x) | Self::In(x) => x.pos = new_pos,
|
||||||
|
Self::True(pos) | Self::False(pos) | Self::Unit(pos) => *pos = new_pos,
|
||||||
|
Self::Dot(x) | Self::Index(x) => x.pos = new_pos,
|
||||||
|
Self::Custom(x) => x.pos = new_pos,
|
||||||
|
}
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Is the expression pure?
|
||||||
|
///
|
||||||
|
/// A pure expression has no side effects.
|
||||||
|
pub fn is_pure(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::Expr(x) => x.is_pure(),
|
||||||
|
|
||||||
|
Self::Array(x) => x.0.iter().all(Self::is_pure),
|
||||||
|
|
||||||
|
Self::Index(x) | Self::And(x) | Self::Or(x) | Self::In(x) => {
|
||||||
|
x.lhs.is_pure() && x.rhs.is_pure()
|
||||||
|
}
|
||||||
|
|
||||||
|
Self::Stmt(x) => x.0.is_pure(),
|
||||||
|
|
||||||
|
Self::Variable(_) => true,
|
||||||
|
|
||||||
|
_ => self.is_constant(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Is the expression the unit `()` literal?
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn is_unit(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::Unit(_) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Is the expression a simple constant literal?
|
||||||
|
pub fn is_literal(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::Expr(x) => x.is_literal(),
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
Self::FloatConstant(_) => true,
|
||||||
|
|
||||||
|
Self::IntegerConstant(_)
|
||||||
|
| Self::CharConstant(_)
|
||||||
|
| Self::StringConstant(_)
|
||||||
|
| Self::FnPointer(_)
|
||||||
|
| Self::True(_)
|
||||||
|
| Self::False(_)
|
||||||
|
| Self::Unit(_) => true,
|
||||||
|
|
||||||
|
// An array literal is literal if all items are literals
|
||||||
|
Self::Array(x) => x.0.iter().all(Self::is_literal),
|
||||||
|
|
||||||
|
// An map literal is literal if all items are literals
|
||||||
|
Self::Map(x) => x.0.iter().map(|(_, expr)| expr).all(Self::is_literal),
|
||||||
|
|
||||||
|
// Check in expression
|
||||||
|
Self::In(x) => match (&x.lhs, &x.rhs) {
|
||||||
|
(Self::StringConstant(_), Self::StringConstant(_))
|
||||||
|
| (Self::CharConstant(_), Self::StringConstant(_)) => true,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Is the expression a constant?
|
||||||
|
pub fn is_constant(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::Expr(x) => x.is_constant(),
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
Self::FloatConstant(_) => true,
|
||||||
|
|
||||||
|
Self::IntegerConstant(_)
|
||||||
|
| Self::CharConstant(_)
|
||||||
|
| Self::StringConstant(_)
|
||||||
|
| Self::FnPointer(_)
|
||||||
|
| Self::True(_)
|
||||||
|
| Self::False(_)
|
||||||
|
| Self::Unit(_) => true,
|
||||||
|
|
||||||
|
// An array literal is constant if all items are constant
|
||||||
|
Self::Array(x) => x.0.iter().all(Self::is_constant),
|
||||||
|
|
||||||
|
// An map literal is constant if all items are constant
|
||||||
|
Self::Map(x) => x.0.iter().map(|(_, expr)| expr).all(Self::is_constant),
|
||||||
|
|
||||||
|
// Check in expression
|
||||||
|
Self::In(x) => match (&x.lhs, &x.rhs) {
|
||||||
|
(Self::StringConstant(_), Self::StringConstant(_))
|
||||||
|
| (Self::CharConstant(_), Self::StringConstant(_)) => true,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Is a particular token allowed as a postfix operator to this expression?
|
||||||
|
pub fn is_valid_postfix(&self, token: &Token) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::Expr(x) => x.is_valid_postfix(token),
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
Self::FloatConstant(_) => false,
|
||||||
|
|
||||||
|
Self::IntegerConstant(_)
|
||||||
|
| Self::CharConstant(_)
|
||||||
|
| Self::FnPointer(_)
|
||||||
|
| Self::In(_)
|
||||||
|
| Self::And(_)
|
||||||
|
| Self::Or(_)
|
||||||
|
| Self::True(_)
|
||||||
|
| Self::False(_)
|
||||||
|
| Self::Unit(_) => false,
|
||||||
|
|
||||||
|
Self::StringConstant(_)
|
||||||
|
| Self::Stmt(_)
|
||||||
|
| Self::FnCall(_)
|
||||||
|
| Self::Dot(_)
|
||||||
|
| Self::Index(_)
|
||||||
|
| Self::Array(_)
|
||||||
|
| Self::Map(_) => match token {
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
Token::LeftBracket => true,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
|
||||||
|
Self::Variable(_) => match token {
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
Token::LeftBracket => true,
|
||||||
|
Token::LeftParen => true,
|
||||||
|
Token::Bang => true,
|
||||||
|
Token::DoubleColon => true,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
|
||||||
|
Self::Property(_) => match token {
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
Token::LeftBracket => true,
|
||||||
|
Token::LeftParen => true,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
|
||||||
|
Self::Custom(_) => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert a `Variable` into a `Property`. All other variants are untouched.
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn into_property(self) -> Self {
|
||||||
|
match self {
|
||||||
|
Self::Variable(x) if x.1.is_none() => {
|
||||||
|
let Ident { name, pos } = x.0;
|
||||||
|
let getter = make_getter(&name);
|
||||||
|
let setter = make_setter(&name);
|
||||||
|
Self::Property(Box::new(((name.into(), getter, setter), pos)))
|
||||||
|
}
|
||||||
|
_ => self,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
//! Helper module which defines the `Any` trait to to allow dynamic value handling.
|
//! Helper module which defines the `Any` trait to to allow dynamic value handling.
|
||||||
|
|
||||||
use crate::fn_native::{FnPtr, SendSync};
|
use crate::fn_native::{FnPtr, SendSync};
|
||||||
use crate::parser::{ImmutableString, INT};
|
|
||||||
use crate::r#unsafe::{unsafe_cast_box, unsafe_try_cast};
|
use crate::r#unsafe::{unsafe_cast_box, unsafe_try_cast};
|
||||||
|
use crate::utils::ImmutableString;
|
||||||
|
use crate::INT;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
use crate::fn_native::{shared_try_take, Locked, Shared};
|
use crate::fn_native::{shared_try_take, Locked, Shared};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
use crate::parser::FLOAT;
|
use crate::FLOAT;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
use crate::engine::Array;
|
use crate::engine::Array;
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
//! Main module defining the script evaluation `Engine`.
|
//! Main module defining the script evaluation `Engine`.
|
||||||
|
|
||||||
|
use crate::ast::{BinaryExpr, Expr, Ident, ReturnType, Stmt};
|
||||||
use crate::dynamic::{map_std_type_name, Dynamic, Union, Variant};
|
use crate::dynamic::{map_std_type_name, Dynamic, Union, Variant};
|
||||||
use crate::fn_call::run_builtin_op_assignment;
|
use crate::fn_call::run_builtin_op_assignment;
|
||||||
use crate::fn_native::{Callback, FnPtr, OnVarCallback};
|
use crate::fn_native::{Callback, FnPtr, OnVarCallback};
|
||||||
use crate::module::{Module, ModuleRef};
|
use crate::module::{Module, ModuleRef};
|
||||||
use crate::optimize::OptimizationLevel;
|
use crate::optimize::OptimizationLevel;
|
||||||
use crate::packages::{Package, PackagesCollection, StandardPackage};
|
use crate::packages::{Package, PackagesCollection, StandardPackage};
|
||||||
use crate::parser::{BinaryExpr, Expr, Ident, ReturnType, Stmt};
|
|
||||||
use crate::r#unsafe::unsafe_cast_var_name_to_lifetime;
|
use crate::r#unsafe::unsafe_cast_var_name_to_lifetime;
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::scope::{EntryType as ScopeEntryType, Scope};
|
use crate::scope::{EntryType as ScopeEntryType, Scope};
|
||||||
@ -15,7 +15,7 @@ use crate::token::Position;
|
|||||||
use crate::{calc_native_fn_hash, StaticVec};
|
use crate::{calc_native_fn_hash, StaticVec};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
use crate::parser::INT;
|
use crate::INT;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
use crate::module::ModuleResolver;
|
use crate::module::ModuleResolver;
|
||||||
@ -389,11 +389,6 @@ pub struct State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
/// Create a new `State`.
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Default::default()
|
|
||||||
}
|
|
||||||
/// Is the state currently at global (root) level?
|
/// Is the state currently at global (root) level?
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn is_global(&self) -> bool {
|
pub fn is_global(&self) -> bool {
|
||||||
@ -461,8 +456,8 @@ impl<'e, 'x, 'px, 'a, 's, 'm, 'pm, 't, 'pt> EvalContext<'e, 'x, 'px, 'a, 's, 'm,
|
|||||||
#[cfg(feature = "internals")]
|
#[cfg(feature = "internals")]
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn imports(&self) -> &'a Imports {
|
pub fn imports<'z: 'a>(&'z self) -> &'a Imports {
|
||||||
self.mods.as_ref()
|
self.mods
|
||||||
}
|
}
|
||||||
/// Get an iterator over the namespaces containing definition of all script-defined functions.
|
/// Get an iterator over the namespaces containing definition of all script-defined functions.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
use crate::ast::AST;
|
use crate::ast::AST;
|
||||||
use crate::dynamic::{Dynamic, Variant};
|
use crate::dynamic::{Dynamic, Variant};
|
||||||
use crate::engine::{Engine, EvalContext, Imports, State};
|
use crate::engine::{Engine, EvalContext, Imports};
|
||||||
use crate::fn_native::{FnCallArgs, NativeCallContext, SendSync};
|
use crate::fn_native::{FnCallArgs, NativeCallContext, SendSync};
|
||||||
use crate::optimize::OptimizationLevel;
|
use crate::optimize::OptimizationLevel;
|
||||||
use crate::parse_error::ParseError;
|
use crate::parse_error::ParseError;
|
||||||
@ -1619,7 +1619,7 @@ impl Engine {
|
|||||||
.get_script_fn(name, args.len(), true)
|
.get_script_fn(name, args.len(), true)
|
||||||
.ok_or_else(|| EvalAltResult::ErrorFunctionNotFound(name.into(), Position::none()))?;
|
.ok_or_else(|| EvalAltResult::ErrorFunctionNotFound(name.into(), Position::none()))?;
|
||||||
|
|
||||||
let mut state = State::new();
|
let mut state = Default::default();
|
||||||
let mut mods = Default::default();
|
let mut mods = Default::default();
|
||||||
|
|
||||||
// Check for data race.
|
// Check for data race.
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
//! Implement function-calling mechanism for `Engine`.
|
//! Implement function-calling mechanism for `Engine`.
|
||||||
|
|
||||||
|
use crate::ast::{Expr, Stmt};
|
||||||
use crate::dynamic::Dynamic;
|
use crate::dynamic::Dynamic;
|
||||||
use crate::engine::{
|
use crate::engine::{
|
||||||
search_imports, Engine, Imports, State, KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR,
|
search_imports, Engine, Imports, State, KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR,
|
||||||
@ -10,21 +11,21 @@ use crate::fn_native::{FnCallArgs, FnPtr};
|
|||||||
use crate::module::{Module, ModuleRef};
|
use crate::module::{Module, ModuleRef};
|
||||||
use crate::optimize::OptimizationLevel;
|
use crate::optimize::OptimizationLevel;
|
||||||
use crate::parse_error::ParseErrorType;
|
use crate::parse_error::ParseErrorType;
|
||||||
use crate::parser::{Expr, ImmutableString, Stmt, INT};
|
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::scope::Scope;
|
use crate::scope::Scope;
|
||||||
use crate::stdlib::ops::Deref;
|
use crate::stdlib::ops::Deref;
|
||||||
use crate::token::Position;
|
use crate::token::Position;
|
||||||
use crate::{calc_native_fn_hash, calc_script_fn_hash, StaticVec};
|
use crate::utils::ImmutableString;
|
||||||
|
use crate::{calc_native_fn_hash, calc_script_fn_hash, StaticVec, INT};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
use crate::{
|
use crate::{
|
||||||
parser::ScriptFnDef, r#unsafe::unsafe_cast_var_name_to_lifetime,
|
ast::ScriptFnDef, r#unsafe::unsafe_cast_var_name_to_lifetime,
|
||||||
scope::EntryType as ScopeEntryType,
|
scope::EntryType as ScopeEntryType,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
use crate::parser::FLOAT;
|
use crate::FLOAT;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
use crate::engine::{FN_IDX_GET, FN_IDX_SET};
|
use crate::engine::{FN_IDX_GET, FN_IDX_SET};
|
||||||
@ -41,7 +42,6 @@ use crate::scope::Entry as ScopeEntry;
|
|||||||
|
|
||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
any::{type_name, TypeId},
|
any::{type_name, TypeId},
|
||||||
borrow::Cow,
|
|
||||||
boxed::Box,
|
boxed::Box,
|
||||||
convert::TryFrom,
|
convert::TryFrom,
|
||||||
format,
|
format,
|
||||||
@ -51,6 +51,9 @@ use crate::stdlib::{
|
|||||||
vec::Vec,
|
vec::Vec,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
use crate::stdlib::borrow::Cow;
|
||||||
|
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
use num_traits::float::Float;
|
use num_traits::float::Float;
|
||||||
@ -628,7 +631,7 @@ impl Engine {
|
|||||||
statements: impl IntoIterator<Item = &'a Stmt>,
|
statements: impl IntoIterator<Item = &'a Stmt>,
|
||||||
lib: &[&Module],
|
lib: &[&Module],
|
||||||
) -> Result<(Dynamic, u64), Box<EvalAltResult>> {
|
) -> Result<(Dynamic, u64), Box<EvalAltResult>> {
|
||||||
let mut state = State::new();
|
let mut state = Default::default();
|
||||||
|
|
||||||
statements
|
statements
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
//! Module defining interfaces to native-Rust functions.
|
//! Module defining interfaces to native-Rust functions.
|
||||||
|
|
||||||
|
use crate::ast::{FnAccess, ScriptFnDef};
|
||||||
use crate::dynamic::Dynamic;
|
use crate::dynamic::Dynamic;
|
||||||
use crate::engine::{Engine, EvalContext};
|
use crate::engine::{Engine, EvalContext};
|
||||||
use crate::module::Module;
|
use crate::module::Module;
|
||||||
use crate::parser::{FnAccess, ScriptFnDef};
|
|
||||||
use crate::plugin::PluginFunction;
|
use crate::plugin::PluginFunction;
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::token::{is_valid_identifier, Position};
|
use crate::token::{is_valid_identifier, Position};
|
||||||
|
@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
|
use crate::ast::FnAccess;
|
||||||
use crate::dynamic::{Dynamic, DynamicWriteLock, Variant};
|
use crate::dynamic::{Dynamic, DynamicWriteLock, Variant};
|
||||||
use crate::engine::Engine;
|
use crate::engine::Engine;
|
||||||
use crate::fn_native::{CallableFunction, FnAny, FnCallArgs, NativeCallContext, SendSync};
|
use crate::fn_native::{CallableFunction, FnAny, FnCallArgs, NativeCallContext, SendSync};
|
||||||
use crate::parser::FnAccess;
|
|
||||||
use crate::r#unsafe::unsafe_cast_box;
|
use crate::r#unsafe::unsafe_cast_box;
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::utils::ImmutableString;
|
use crate::utils::ImmutableString;
|
||||||
|
29
src/lib.rs
29
src/lib.rs
@ -83,6 +83,24 @@ mod token;
|
|||||||
mod r#unsafe;
|
mod r#unsafe;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
|
/// The system integer type.
|
||||||
|
///
|
||||||
|
/// If the `only_i32` feature is enabled, this will be `i32` instead.
|
||||||
|
#[cfg(not(feature = "only_i32"))]
|
||||||
|
pub type INT = i64;
|
||||||
|
|
||||||
|
/// The system integer type.
|
||||||
|
///
|
||||||
|
/// If the `only_i32` feature is not enabled, this will be `i64` instead.
|
||||||
|
#[cfg(feature = "only_i32")]
|
||||||
|
pub type INT = i32;
|
||||||
|
|
||||||
|
/// The system floating-point type.
|
||||||
|
///
|
||||||
|
/// Not available under the `no_float` feature.
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
pub type FLOAT = f64;
|
||||||
|
|
||||||
pub use ast::AST;
|
pub use ast::AST;
|
||||||
pub use dynamic::Dynamic;
|
pub use dynamic::Dynamic;
|
||||||
pub use engine::{Engine, EvalContext};
|
pub use engine::{Engine, EvalContext};
|
||||||
@ -90,11 +108,11 @@ pub use fn_native::{FnPtr, NativeCallContext};
|
|||||||
pub use fn_register::{RegisterFn, RegisterResultFn};
|
pub use fn_register::{RegisterFn, RegisterResultFn};
|
||||||
pub use module::Module;
|
pub use module::Module;
|
||||||
pub use parse_error::{ParseError, ParseErrorType};
|
pub use parse_error::{ParseError, ParseErrorType};
|
||||||
pub use parser::{ImmutableString, INT};
|
|
||||||
pub use result::EvalAltResult;
|
pub use result::EvalAltResult;
|
||||||
pub use scope::Scope;
|
pub use scope::Scope;
|
||||||
pub use syntax::Expression;
|
pub use syntax::Expression;
|
||||||
pub use token::Position;
|
pub use token::Position;
|
||||||
|
pub use utils::ImmutableString;
|
||||||
|
|
||||||
#[cfg(feature = "internals")]
|
#[cfg(feature = "internals")]
|
||||||
pub use utils::{calc_native_fn_hash, calc_script_fn_hash};
|
pub use utils::{calc_native_fn_hash, calc_script_fn_hash};
|
||||||
@ -105,9 +123,7 @@ pub(crate) use utils::{calc_native_fn_hash, calc_script_fn_hash};
|
|||||||
pub use rhai_codegen::*;
|
pub use rhai_codegen::*;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
pub use parser::FnAccess;
|
pub use ast::FnAccess;
|
||||||
#[cfg(feature = "no_function")]
|
|
||||||
pub use parser::FnAccess;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
pub use fn_func::Func;
|
pub use fn_func::Func;
|
||||||
@ -118,9 +134,6 @@ pub use engine::Array;
|
|||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
pub use engine::Map;
|
pub use engine::Map;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
|
||||||
pub use parser::FLOAT;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
pub use module::ModuleResolver;
|
pub use module::ModuleResolver;
|
||||||
|
|
||||||
@ -151,7 +164,7 @@ pub use token::{get_next_token, parse_string_literal, InputStream, Token, Tokeni
|
|||||||
|
|
||||||
#[cfg(feature = "internals")]
|
#[cfg(feature = "internals")]
|
||||||
#[deprecated(note = "this type is volatile and may change")]
|
#[deprecated(note = "this type is volatile and may change")]
|
||||||
pub use parser::{
|
pub use ast::{
|
||||||
BinaryExpr, CustomExpr, Expr, FloatWrapper, Ident, IdentX, ReturnType, ScriptFnDef, Stmt,
|
BinaryExpr, CustomExpr, Expr, FloatWrapper, Ident, IdentX, ReturnType, ScriptFnDef, Stmt,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
//! Module defining external-loaded modules for Rhai.
|
//! Module defining external-loaded modules for Rhai.
|
||||||
|
|
||||||
|
use crate::ast::FnAccess;
|
||||||
use crate::dynamic::{Dynamic, Variant};
|
use crate::dynamic::{Dynamic, Variant};
|
||||||
use crate::fn_native::{CallableFunction, FnCallArgs, IteratorFn, NativeCallContext, SendSync};
|
use crate::fn_native::{CallableFunction, FnCallArgs, IteratorFn, NativeCallContext, SendSync};
|
||||||
use crate::fn_register::by_value as cast_arg;
|
use crate::fn_register::by_value as cast_arg;
|
||||||
use crate::parser::FnAccess;
|
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::token::{Position, Token};
|
use crate::token::{Position, Token};
|
||||||
use crate::utils::{ImmutableString, StraightHasherBuilder};
|
use crate::utils::{ImmutableString, StraightHasherBuilder};
|
||||||
use crate::{calc_native_fn_hash, calc_script_fn_hash, StaticVec};
|
use crate::{calc_native_fn_hash, calc_script_fn_hash, StaticVec};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
use crate::{fn_native::Shared, parser::ScriptFnDef};
|
use crate::{fn_native::Shared, ast::ScriptFnDef};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//! Module implementing the AST optimizer.
|
//! Module implementing the AST optimizer.
|
||||||
|
|
||||||
use crate::ast::AST;
|
use crate::ast::{BinaryExpr, CustomExpr, Expr, ScriptFnDef, Stmt, AST};
|
||||||
use crate::dynamic::Dynamic;
|
use crate::dynamic::Dynamic;
|
||||||
use crate::engine::{
|
use crate::engine::{
|
||||||
Engine, KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_IS_DEF_FN, KEYWORD_IS_DEF_VAR, KEYWORD_PRINT,
|
Engine, KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_IS_DEF_FN, KEYWORD_IS_DEF_VAR, KEYWORD_PRINT,
|
||||||
@ -8,13 +8,13 @@ use crate::engine::{
|
|||||||
};
|
};
|
||||||
use crate::fn_call::run_builtin_binary_op;
|
use crate::fn_call::run_builtin_binary_op;
|
||||||
use crate::module::Module;
|
use crate::module::Module;
|
||||||
use crate::parser::{map_dynamic_to_expr, BinaryExpr, CustomExpr, Expr, ScriptFnDef, Stmt};
|
use crate::parser::map_dynamic_to_expr;
|
||||||
use crate::scope::{Entry as ScopeEntry, Scope};
|
use crate::scope::{Entry as ScopeEntry, Scope};
|
||||||
use crate::token::{is_valid_identifier, Position};
|
use crate::token::{is_valid_identifier, Position};
|
||||||
use crate::{calc_native_fn_hash, StaticVec};
|
use crate::{calc_native_fn_hash, StaticVec};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
use crate::parser::ReturnType;
|
use crate::ast::ReturnType;
|
||||||
|
|
||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
boxed::Box,
|
boxed::Box,
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
use crate::def_package;
|
use crate::def_package;
|
||||||
use crate::parser::INT;
|
|
||||||
use crate::plugin::*;
|
use crate::plugin::*;
|
||||||
|
use crate::INT;
|
||||||
|
|
||||||
use crate::{result::EvalAltResult, token::Position};
|
use crate::{result::EvalAltResult, token::Position};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
use crate::parser::FLOAT;
|
use crate::FLOAT;
|
||||||
|
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
@ -5,10 +5,11 @@ use crate::def_package;
|
|||||||
use crate::dynamic::Dynamic;
|
use crate::dynamic::Dynamic;
|
||||||
use crate::engine::Array;
|
use crate::engine::Array;
|
||||||
use crate::fn_native::{FnPtr, NativeCallContext};
|
use crate::fn_native::{FnPtr, NativeCallContext};
|
||||||
use crate::parser::{ImmutableString, INT};
|
|
||||||
use crate::plugin::*;
|
use crate::plugin::*;
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::token::Position;
|
use crate::token::Position;
|
||||||
|
use crate::utils::ImmutableString;
|
||||||
|
use crate::INT;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
use crate::engine::Map;
|
use crate::engine::Map;
|
||||||
@ -40,12 +41,12 @@ macro_rules! gen_array_functions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[rhai_fn(return_raw)]
|
#[rhai_fn(return_raw)]
|
||||||
pub fn pad(context: NativeCallContext, list: &mut Array, len: INT, item: $arg_type) -> Result<Dynamic, Box<EvalAltResult>> {
|
pub fn pad(_context: NativeCallContext, list: &mut Array, len: INT, item: $arg_type) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
// Check if array will be over max size limit
|
// Check if array will be over max size limit
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
if context.engine().max_array_size() > 0 && len > 0 && (len as usize) > context.engine().max_array_size() {
|
if _context.engine().max_array_size() > 0 && len > 0 && (len as usize) > _context.engine().max_array_size() {
|
||||||
return EvalAltResult::ErrorDataTooLarge(
|
return EvalAltResult::ErrorDataTooLarge(
|
||||||
"Size of array".to_string(), context.engine().max_array_size(), len as usize, Position::none(),
|
"Size of array".to_string(), _context.engine().max_array_size(), len as usize, Position::none(),
|
||||||
).into();
|
).into();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use crate::def_package;
|
use crate::def_package;
|
||||||
use crate::dynamic::Dynamic;
|
use crate::dynamic::Dynamic;
|
||||||
use crate::parser::ImmutableString;
|
|
||||||
use crate::plugin::*;
|
use crate::plugin::*;
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
|
use crate::utils::ImmutableString;
|
||||||
|
|
||||||
def_package!(crate:EvalPackage:"Disable 'eval'.", lib, {
|
def_package!(crate:EvalPackage:"Disable 'eval'.", lib, {
|
||||||
combine_with_exported_module!(lib, "eval", eval_override);
|
combine_with_exported_module!(lib, "eval", eval_override);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::def_package;
|
use crate::def_package;
|
||||||
use crate::dynamic::Variant;
|
use crate::dynamic::Variant;
|
||||||
use crate::parser::INT;
|
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
|
use crate::INT;
|
||||||
|
|
||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
boxed::Box,
|
boxed::Box,
|
||||||
|
@ -3,8 +3,9 @@
|
|||||||
use crate::def_package;
|
use crate::def_package;
|
||||||
use crate::dynamic::Dynamic;
|
use crate::dynamic::Dynamic;
|
||||||
use crate::engine::Map;
|
use crate::engine::Map;
|
||||||
use crate::parser::{ImmutableString, INT};
|
|
||||||
use crate::plugin::*;
|
use crate::plugin::*;
|
||||||
|
use crate::utils::ImmutableString;
|
||||||
|
use crate::INT;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
use crate::engine::Array;
|
use crate::engine::Array;
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
use crate::def_package;
|
use crate::def_package;
|
||||||
use crate::parser::INT;
|
|
||||||
use crate::plugin::*;
|
use crate::plugin::*;
|
||||||
use crate::token::Position;
|
use crate::token::Position;
|
||||||
|
use crate::INT;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
use crate::parser::FLOAT;
|
use crate::FLOAT;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
@ -111,7 +111,7 @@ mod int_functions {
|
|||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
#[export_module]
|
#[export_module]
|
||||||
mod trig_functions {
|
mod trig_functions {
|
||||||
use crate::parser::FLOAT;
|
use crate::FLOAT;
|
||||||
|
|
||||||
pub fn sin(x: FLOAT) -> FLOAT {
|
pub fn sin(x: FLOAT) -> FLOAT {
|
||||||
x.to_radians().sin()
|
x.to_radians().sin()
|
||||||
@ -154,7 +154,7 @@ mod trig_functions {
|
|||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
#[export_module]
|
#[export_module]
|
||||||
mod float_functions {
|
mod float_functions {
|
||||||
use crate::parser::FLOAT;
|
use crate::FLOAT;
|
||||||
|
|
||||||
pub fn sqrt(x: FLOAT) -> FLOAT {
|
pub fn sqrt(x: FLOAT) -> FLOAT {
|
||||||
x.sqrt()
|
x.sqrt()
|
||||||
|
@ -3,8 +3,9 @@
|
|||||||
use crate::def_package;
|
use crate::def_package;
|
||||||
use crate::engine::{FN_TO_STRING, KEYWORD_DEBUG, KEYWORD_PRINT};
|
use crate::engine::{FN_TO_STRING, KEYWORD_DEBUG, KEYWORD_PRINT};
|
||||||
use crate::fn_native::FnPtr;
|
use crate::fn_native::FnPtr;
|
||||||
use crate::parser::{ImmutableString, INT};
|
|
||||||
use crate::plugin::*;
|
use crate::plugin::*;
|
||||||
|
use crate::utils::ImmutableString;
|
||||||
|
use crate::INT;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
use crate::engine::Array;
|
use crate::engine::Array;
|
||||||
|
@ -3,9 +3,10 @@
|
|||||||
use crate::def_package;
|
use crate::def_package;
|
||||||
use crate::dynamic::Dynamic;
|
use crate::dynamic::Dynamic;
|
||||||
use crate::fn_native::FnPtr;
|
use crate::fn_native::FnPtr;
|
||||||
use crate::parser::{ImmutableString, INT};
|
|
||||||
use crate::plugin::*;
|
use crate::plugin::*;
|
||||||
|
use crate::utils::ImmutableString;
|
||||||
use crate::StaticVec;
|
use crate::StaticVec;
|
||||||
|
use crate::INT;
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
use crate::{result::EvalAltResult, token::Position};
|
use crate::{result::EvalAltResult, token::Position};
|
||||||
|
@ -4,12 +4,12 @@ use super::{arithmetic::make_err as make_arithmetic_err, math_basic::MAX_INT};
|
|||||||
|
|
||||||
use crate::def_package;
|
use crate::def_package;
|
||||||
use crate::dynamic::Dynamic;
|
use crate::dynamic::Dynamic;
|
||||||
use crate::parser::INT;
|
|
||||||
use crate::plugin::*;
|
use crate::plugin::*;
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
|
use crate::INT;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
use crate::parser::FLOAT;
|
use crate::FLOAT;
|
||||||
|
|
||||||
use crate::stdlib::boxed::Box;
|
use crate::stdlib::boxed::Box;
|
||||||
|
|
||||||
|
817
src/parser.rs
817
src/parser.rs
@ -1,35 +1,36 @@
|
|||||||
//! Main module defining the lexer and parser.
|
//! Main module defining the lexer and parser.
|
||||||
|
|
||||||
use crate::ast::AST;
|
use crate::ast::{BinaryExpr, CustomExpr, Expr, Ident, IdentX, ReturnType, ScriptFnDef, Stmt, AST};
|
||||||
use crate::dynamic::{Dynamic, Union};
|
use crate::dynamic::{Dynamic, Union};
|
||||||
use crate::engine::{Engine, KEYWORD_THIS, MARKER_BLOCK, MARKER_EXPR, MARKER_IDENT};
|
use crate::engine::{Engine, KEYWORD_THIS, MARKER_BLOCK, MARKER_EXPR, MARKER_IDENT};
|
||||||
use crate::fn_native::{FnPtr, Shared};
|
use crate::module::ModuleRef;
|
||||||
use crate::module::{Module, ModuleRef};
|
|
||||||
use crate::optimize::{optimize_into_ast, OptimizationLevel};
|
use crate::optimize::{optimize_into_ast, OptimizationLevel};
|
||||||
use crate::parse_error::{LexError, ParseError, ParseErrorType};
|
use crate::parse_error::{LexError, ParseError, ParseErrorType};
|
||||||
use crate::scope::{EntryType as ScopeEntryType, Scope};
|
use crate::scope::{EntryType as ScopeEntryType, Scope};
|
||||||
use crate::syntax::{CustomSyntax, FnCustomSyntaxEval};
|
use crate::syntax::CustomSyntax;
|
||||||
use crate::token::{is_keyword_function, is_valid_identifier, Position, Token, TokenStream};
|
use crate::token::{is_keyword_function, is_valid_identifier, Position, Token, TokenStream};
|
||||||
use crate::utils::StraightHasherBuilder;
|
use crate::utils::StraightHasherBuilder;
|
||||||
use crate::{calc_script_fn_hash, StaticVec};
|
use crate::{calc_script_fn_hash, StaticVec};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
use crate::engine::Array;
|
use crate::ast::FloatWrapper;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
use crate::engine::{make_getter, make_setter, Map, KEYWORD_EVAL, KEYWORD_FN_PTR};
|
use crate::engine::{make_getter, make_setter, KEYWORD_EVAL, KEYWORD_FN_PTR};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
use crate::engine::{FN_ANONYMOUS, KEYWORD_FN_PTR_CURRY};
|
use crate::{
|
||||||
|
ast::FnAccess,
|
||||||
|
engine::{FN_ANONYMOUS, KEYWORD_FN_PTR_CURRY},
|
||||||
|
utils::ImmutableString,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
any::TypeId,
|
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
boxed::Box,
|
boxed::Box,
|
||||||
char,
|
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
fmt, format,
|
format,
|
||||||
hash::{Hash, Hasher},
|
hash::Hash,
|
||||||
iter::empty,
|
iter::empty,
|
||||||
num::NonZeroUsize,
|
num::NonZeroUsize,
|
||||||
string::{String, ToString},
|
string::{String, ToString},
|
||||||
@ -37,138 +38,21 @@ use crate::stdlib::{
|
|||||||
vec::Vec,
|
vec::Vec,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
use crate::stdlib::hash::Hasher;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_std"))]
|
#[cfg(not(feature = "no_std"))]
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
use crate::stdlib::collections::hash_map::DefaultHasher;
|
use crate::stdlib::collections::hash_map::DefaultHasher;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_closure"))]
|
|
||||||
use crate::stdlib::collections::HashSet;
|
|
||||||
|
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
use ahash::AHasher;
|
use ahash::AHasher;
|
||||||
|
|
||||||
/// The system integer type.
|
|
||||||
///
|
|
||||||
/// If the `only_i32` feature is enabled, this will be `i32` instead.
|
|
||||||
#[cfg(not(feature = "only_i32"))]
|
|
||||||
pub type INT = i64;
|
|
||||||
|
|
||||||
/// The system integer type.
|
|
||||||
///
|
|
||||||
/// If the `only_i32` feature is not enabled, this will be `i64` instead.
|
|
||||||
#[cfg(feature = "only_i32")]
|
|
||||||
pub type INT = i32;
|
|
||||||
|
|
||||||
/// The system floating-point type.
|
|
||||||
///
|
|
||||||
/// Not available under the `no_float` feature.
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
|
||||||
pub type FLOAT = f64;
|
|
||||||
|
|
||||||
type PERR = ParseErrorType;
|
type PERR = ParseErrorType;
|
||||||
|
|
||||||
pub use crate::utils::ImmutableString;
|
|
||||||
|
|
||||||
type FunctionsLib = HashMap<u64, ScriptFnDef, StraightHasherBuilder>;
|
type FunctionsLib = HashMap<u64, ScriptFnDef, StraightHasherBuilder>;
|
||||||
|
|
||||||
/// A type representing the access mode of a scripted function.
|
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
|
|
||||||
pub enum FnAccess {
|
|
||||||
/// Public function.
|
|
||||||
Public,
|
|
||||||
/// Private function.
|
|
||||||
Private,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for FnAccess {
|
|
||||||
#[inline(always)]
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
Self::Private => write!(f, "private"),
|
|
||||||
Self::Public => write!(f, "public"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FnAccess {
|
|
||||||
/// Is this access mode private?
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn is_private(self) -> bool {
|
|
||||||
match self {
|
|
||||||
Self::Public => false,
|
|
||||||
Self::Private => true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// Is this access mode public?
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn is_public(self) -> bool {
|
|
||||||
match self {
|
|
||||||
Self::Public => true,
|
|
||||||
Self::Private => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// _[INTERNALS]_ A type containing information on a scripted function.
|
|
||||||
/// Exported under the `internals` feature only.
|
|
||||||
///
|
|
||||||
/// ## WARNING
|
|
||||||
///
|
|
||||||
/// This type is volatile and may change.
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct ScriptFnDef {
|
|
||||||
/// Function name.
|
|
||||||
pub name: ImmutableString,
|
|
||||||
/// Function access mode.
|
|
||||||
pub access: FnAccess,
|
|
||||||
/// Names of function parameters.
|
|
||||||
pub params: StaticVec<String>,
|
|
||||||
/// Access to external variables.
|
|
||||||
#[cfg(not(feature = "no_closure"))]
|
|
||||||
pub externals: HashSet<String>,
|
|
||||||
/// Function body.
|
|
||||||
pub body: Stmt,
|
|
||||||
/// Position of the function definition.
|
|
||||||
pub pos: Position,
|
|
||||||
/// Encapsulated running environment, if any.
|
|
||||||
pub lib: Option<Shared<Module>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for ScriptFnDef {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"{}{}({})",
|
|
||||||
if self.access.is_private() {
|
|
||||||
"private "
|
|
||||||
} else {
|
|
||||||
""
|
|
||||||
},
|
|
||||||
self.name,
|
|
||||||
self.params
|
|
||||||
.iter()
|
|
||||||
.map(|s| s.as_str())
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join(",")
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// _[INTERNALS]_ A type encapsulating the mode of a `return`/`throw` statement.
|
|
||||||
/// Exported under the `internals` feature only.
|
|
||||||
///
|
|
||||||
/// ## WARNING
|
|
||||||
///
|
|
||||||
/// This type is volatile and may change.
|
|
||||||
#[derive(Debug, Eq, PartialEq, Clone, Copy, Hash)]
|
|
||||||
pub enum ReturnType {
|
|
||||||
/// `return` statement.
|
|
||||||
Return,
|
|
||||||
/// `throw` statement.
|
|
||||||
Exception,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct ParseState<'e> {
|
struct ParseState<'e> {
|
||||||
/// Reference to the scripting `Engine`.
|
/// Reference to the scripting `Engine`.
|
||||||
@ -317,664 +201,6 @@ impl ParseSettings {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An identifier containing a string name and a position.
|
|
||||||
#[derive(Debug, Clone, Hash)]
|
|
||||||
pub struct Ident {
|
|
||||||
pub name: String,
|
|
||||||
pub pos: Position,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Ident {
|
|
||||||
/// Create a new `Identifier`.
|
|
||||||
pub fn new(name: String, pos: Position) -> Self {
|
|
||||||
Self { name, pos }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An identifier containing an immutable name and a position.
|
|
||||||
#[derive(Debug, Clone, Hash)]
|
|
||||||
pub struct IdentX {
|
|
||||||
pub name: ImmutableString,
|
|
||||||
pub pos: Position,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IdentX {
|
|
||||||
/// Create a new `Identifier`.
|
|
||||||
pub fn new(name: impl Into<ImmutableString>, pos: Position) -> Self {
|
|
||||||
Self {
|
|
||||||
name: name.into(),
|
|
||||||
pos,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// _[INTERNALS]_ A Rhai 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.
|
|
||||||
#[derive(Debug, Clone, Hash)]
|
|
||||||
pub enum Stmt {
|
|
||||||
/// No-op.
|
|
||||||
Noop(Position),
|
|
||||||
/// if expr { stmt } else { stmt }
|
|
||||||
IfThenElse(Expr, Box<(Stmt, Option<Stmt>)>, Position),
|
|
||||||
/// while expr { stmt }
|
|
||||||
While(Expr, Box<Stmt>, Position),
|
|
||||||
/// loop { stmt }
|
|
||||||
Loop(Box<Stmt>, Position),
|
|
||||||
/// for id in expr { stmt }
|
|
||||||
For(Expr, Box<(String, Stmt)>, Position),
|
|
||||||
/// let id = expr
|
|
||||||
Let(Box<Ident>, Option<Expr>, Position),
|
|
||||||
/// const id = expr
|
|
||||||
Const(Box<Ident>, Option<Expr>, Position),
|
|
||||||
/// expr op= expr
|
|
||||||
Assignment(Box<(Expr, Cow<'static, str>, Expr)>, Position),
|
|
||||||
/// { stmt; ... }
|
|
||||||
Block(Vec<Stmt>, Position),
|
|
||||||
/// try { stmt; ... } catch ( var ) { stmt; ... }
|
|
||||||
TryCatch(Box<(Stmt, Option<Ident>, Stmt, (Position, Position))>),
|
|
||||||
/// expr
|
|
||||||
Expr(Expr),
|
|
||||||
/// continue
|
|
||||||
Continue(Position),
|
|
||||||
/// break
|
|
||||||
Break(Position),
|
|
||||||
/// return/throw
|
|
||||||
ReturnWithVal((ReturnType, Position), Option<Expr>, Position),
|
|
||||||
/// import expr as var
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
|
||||||
Import(Expr, Option<Box<IdentX>>, Position),
|
|
||||||
/// export var as var, ...
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
|
||||||
Export(Vec<(Ident, Option<Ident>)>, Position),
|
|
||||||
/// Convert a variable to shared.
|
|
||||||
#[cfg(not(feature = "no_closure"))]
|
|
||||||
Share(Ident),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Stmt {
|
|
||||||
#[inline(always)]
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::Noop(Default::default())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Stmt {
|
|
||||||
/// Is this statement `Noop`?
|
|
||||||
pub fn is_noop(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
Self::Noop(_) => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the `Position` of this statement.
|
|
||||||
pub fn position(&self) -> Position {
|
|
||||||
match self {
|
|
||||||
Self::Noop(pos)
|
|
||||||
| Self::Continue(pos)
|
|
||||||
| Self::Break(pos)
|
|
||||||
| Self::Block(_, pos)
|
|
||||||
| Self::Assignment(_, pos)
|
|
||||||
| Self::IfThenElse(_, _, pos)
|
|
||||||
| Self::While(_, _, pos)
|
|
||||||
| Self::Loop(_, pos)
|
|
||||||
| Self::For(_, _, pos)
|
|
||||||
| Self::ReturnWithVal((_, pos), _, _) => *pos,
|
|
||||||
|
|
||||||
Self::Let(x, _, _) | Self::Const(x, _, _) => x.pos,
|
|
||||||
Self::TryCatch(x) => (x.3).0,
|
|
||||||
|
|
||||||
Self::Expr(x) => x.position(),
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
|
||||||
Self::Import(_, _, pos) => *pos,
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
|
||||||
Self::Export(_, pos) => *pos,
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_closure"))]
|
|
||||||
Self::Share(Ident { pos, .. }) => *pos,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Override the `Position` of this statement.
|
|
||||||
pub fn set_position(&mut self, new_pos: Position) -> &mut Self {
|
|
||||||
match self {
|
|
||||||
Self::Noop(pos)
|
|
||||||
| Self::Continue(pos)
|
|
||||||
| Self::Break(pos)
|
|
||||||
| Self::Block(_, pos)
|
|
||||||
| Self::Assignment(_, pos)
|
|
||||||
| Self::IfThenElse(_, _, pos)
|
|
||||||
| Self::While(_, _, pos)
|
|
||||||
| Self::Loop(_, pos)
|
|
||||||
| Self::For(_, _, pos)
|
|
||||||
| 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::Expr(x) => {
|
|
||||||
x.set_position(new_pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
|
||||||
Self::Import(_, _, pos) => *pos = new_pos,
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
|
||||||
Self::Export(_, pos) => *pos = new_pos,
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_closure"))]
|
|
||||||
Self::Share(Ident { pos, .. }) => *pos = new_pos,
|
|
||||||
}
|
|
||||||
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Is this statement self-terminated (i.e. no need for a semicolon terminator)?
|
|
||||||
pub fn is_self_terminated(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
Self::IfThenElse(_, _, _)
|
|
||||||
| Self::While(_, _, _)
|
|
||||||
| Self::Loop(_, _)
|
|
||||||
| Self::For(_, _, _)
|
|
||||||
| Self::Block(_, _)
|
|
||||||
| Self::TryCatch(_) => true,
|
|
||||||
|
|
||||||
// A No-op requires a semicolon in order to know it is an empty statement!
|
|
||||||
Self::Noop(_) => false,
|
|
||||||
|
|
||||||
Self::Let(_, _, _)
|
|
||||||
| Self::Const(_, _, _)
|
|
||||||
| Self::Assignment(_, _)
|
|
||||||
| Self::Expr(_)
|
|
||||||
| Self::Continue(_)
|
|
||||||
| Self::Break(_)
|
|
||||||
| Self::ReturnWithVal(_, _, _) => false,
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
|
||||||
Self::Import(_, _, _) | Self::Export(_, _) => false,
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_closure"))]
|
|
||||||
Self::Share(_) => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Is this statement _pure_?
|
|
||||||
pub fn is_pure(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
Self::Noop(_) => true,
|
|
||||||
Self::Expr(expr) => expr.is_pure(),
|
|
||||||
Self::IfThenElse(condition, x, _) if x.1.is_some() => {
|
|
||||||
condition.is_pure() && x.0.is_pure() && x.1.as_ref().unwrap().is_pure()
|
|
||||||
}
|
|
||||||
Self::IfThenElse(condition, x, _) => condition.is_pure() && x.0.is_pure(),
|
|
||||||
Self::While(condition, block, _) => condition.is_pure() && block.is_pure(),
|
|
||||||
Self::Loop(block, _) => block.is_pure(),
|
|
||||||
Self::For(iterable, x, _) => iterable.is_pure() && x.1.is_pure(),
|
|
||||||
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(),
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
|
||||||
Self::Import(_, _, _) => false,
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
|
||||||
Self::Export(_, _) => false,
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_closure"))]
|
|
||||||
Self::Share(_) => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// _[INTERNALS]_ A type wrapping a custom syntax definition.
|
|
||||||
/// Exported under the `internals` feature only.
|
|
||||||
///
|
|
||||||
/// ## WARNING
|
|
||||||
///
|
|
||||||
/// This type is volatile and may change.
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct CustomExpr {
|
|
||||||
pub(crate) keywords: StaticVec<Expr>,
|
|
||||||
pub(crate) func: Shared<FnCustomSyntaxEval>,
|
|
||||||
pub(crate) pos: Position,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for CustomExpr {
|
|
||||||
#[inline(always)]
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
fmt::Debug::fmt(&self.keywords, f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Hash for CustomExpr {
|
|
||||||
#[inline(always)]
|
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
|
||||||
self.keywords.hash(state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CustomExpr {
|
|
||||||
/// Get the keywords for this `CustomExpr`.
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn keywords(&self) -> &[Expr] {
|
|
||||||
&self.keywords
|
|
||||||
}
|
|
||||||
/// Get the implementation function for this `CustomExpr`.
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn func(&self) -> &FnCustomSyntaxEval {
|
|
||||||
self.func.as_ref()
|
|
||||||
}
|
|
||||||
/// Get the position of this `CustomExpr`.
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn position(&self) -> Position {
|
|
||||||
self.pos
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// _[INTERNALS]_ A type wrapping a floating-point number.
|
|
||||||
/// Exported under the `internals` feature only.
|
|
||||||
///
|
|
||||||
/// This type is mainly used to provide a standard `Hash` implementation
|
|
||||||
/// to floating-point numbers, allowing `Expr` to derive `Hash` automatically.
|
|
||||||
///
|
|
||||||
/// ## WARNING
|
|
||||||
///
|
|
||||||
/// This type is volatile and may change.
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
|
||||||
#[derive(Debug, PartialEq, PartialOrd, Clone)]
|
|
||||||
pub struct FloatWrapper(pub FLOAT, pub Position);
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
|
||||||
impl Hash for FloatWrapper {
|
|
||||||
#[inline(always)]
|
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
|
||||||
state.write(&self.0.to_le_bytes());
|
|
||||||
self.1.hash(state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A binary expression structure.
|
|
||||||
#[derive(Debug, Clone, Hash)]
|
|
||||||
pub struct BinaryExpr {
|
|
||||||
pub lhs: Expr,
|
|
||||||
pub rhs: Expr,
|
|
||||||
pub pos: Position,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// _[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.
|
|
||||||
#[derive(Debug, Clone, Hash)]
|
|
||||||
pub enum Expr {
|
|
||||||
/// Integer constant.
|
|
||||||
IntegerConstant(Box<(INT, Position)>),
|
|
||||||
/// Floating-point constant.
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
|
||||||
FloatConstant(Box<FloatWrapper>),
|
|
||||||
/// Character constant.
|
|
||||||
CharConstant(Box<(char, Position)>),
|
|
||||||
/// String constant.
|
|
||||||
StringConstant(Box<IdentX>),
|
|
||||||
/// FnPtr constant.
|
|
||||||
FnPointer(Box<IdentX>),
|
|
||||||
/// Variable access - ((variable name, position), optional modules, hash, optional index)
|
|
||||||
Variable(Box<(Ident, Option<Box<ModuleRef>>, u64, Option<NonZeroUsize>)>),
|
|
||||||
/// Property access.
|
|
||||||
Property(Box<((ImmutableString, String, String), Position)>),
|
|
||||||
/// { stmt }
|
|
||||||
Stmt(Box<(Stmt, Position)>),
|
|
||||||
/// Wrapped expression - should not be optimized away.
|
|
||||||
Expr(Box<Expr>),
|
|
||||||
/// func(expr, ... ) - ((function name, native_only, capture, position), optional modules, hash, arguments, optional default value)
|
|
||||||
/// Use `Cow<'static, str>` because a lot of operators (e.g. `==`, `>=`) are implemented as function calls
|
|
||||||
/// and the function names are predictable, so no need to allocate a new `String`.
|
|
||||||
FnCall(
|
|
||||||
Box<(
|
|
||||||
(Cow<'static, str>, bool, bool, Position),
|
|
||||||
Option<Box<ModuleRef>>,
|
|
||||||
u64,
|
|
||||||
StaticVec<Expr>,
|
|
||||||
Option<bool>, // Default value is `bool` in order for `Expr` to be `Hash`.
|
|
||||||
)>,
|
|
||||||
),
|
|
||||||
/// lhs.rhs
|
|
||||||
Dot(Box<BinaryExpr>),
|
|
||||||
/// expr[expr]
|
|
||||||
Index(Box<BinaryExpr>),
|
|
||||||
/// [ expr, ... ]
|
|
||||||
Array(Box<(StaticVec<Expr>, Position)>),
|
|
||||||
/// #{ name:expr, ... }
|
|
||||||
Map(Box<(StaticVec<(IdentX, Expr)>, Position)>),
|
|
||||||
/// lhs in rhs
|
|
||||||
In(Box<BinaryExpr>),
|
|
||||||
/// lhs && rhs
|
|
||||||
And(Box<BinaryExpr>),
|
|
||||||
/// lhs || rhs
|
|
||||||
Or(Box<BinaryExpr>),
|
|
||||||
/// true
|
|
||||||
True(Position),
|
|
||||||
/// false
|
|
||||||
False(Position),
|
|
||||||
/// ()
|
|
||||||
Unit(Position),
|
|
||||||
/// Custom syntax
|
|
||||||
Custom(Box<CustomExpr>),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Expr {
|
|
||||||
#[inline(always)]
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::Unit(Default::default())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Expr {
|
|
||||||
/// Get the type of an expression.
|
|
||||||
///
|
|
||||||
/// Returns `None` if the expression's result type is not constant.
|
|
||||||
pub fn get_type_id(&self) -> Option<TypeId> {
|
|
||||||
Some(match self {
|
|
||||||
Self::Expr(x) => return x.get_type_id(),
|
|
||||||
|
|
||||||
Self::IntegerConstant(_) => TypeId::of::<INT>(),
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
|
||||||
Self::FloatConstant(_) => TypeId::of::<FLOAT>(),
|
|
||||||
Self::CharConstant(_) => TypeId::of::<char>(),
|
|
||||||
Self::StringConstant(_) => TypeId::of::<ImmutableString>(),
|
|
||||||
Self::FnPointer(_) => TypeId::of::<FnPtr>(),
|
|
||||||
Self::True(_) | Self::False(_) | Self::In(_) | Self::And(_) | Self::Or(_) => {
|
|
||||||
TypeId::of::<bool>()
|
|
||||||
}
|
|
||||||
Self::Unit(_) => TypeId::of::<()>(),
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
|
||||||
Self::Array(_) => TypeId::of::<Array>(),
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
|
||||||
Self::Map(_) => TypeId::of::<Map>(),
|
|
||||||
|
|
||||||
_ => return None,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the `Dynamic` value of a constant expression.
|
|
||||||
///
|
|
||||||
/// Returns `None` if the expression is not constant.
|
|
||||||
pub fn get_constant_value(&self) -> Option<Dynamic> {
|
|
||||||
Some(match self {
|
|
||||||
Self::Expr(x) => return x.get_constant_value(),
|
|
||||||
|
|
||||||
Self::IntegerConstant(x) => x.0.into(),
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
|
||||||
Self::FloatConstant(x) => x.0.into(),
|
|
||||||
Self::CharConstant(x) => x.0.into(),
|
|
||||||
Self::StringConstant(x) => x.name.clone().into(),
|
|
||||||
Self::FnPointer(x) => Dynamic(Union::FnPtr(Box::new(FnPtr::new_unchecked(
|
|
||||||
x.name.clone(),
|
|
||||||
Default::default(),
|
|
||||||
)))),
|
|
||||||
Self::True(_) => true.into(),
|
|
||||||
Self::False(_) => false.into(),
|
|
||||||
Self::Unit(_) => ().into(),
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
|
||||||
Self::Array(x) if x.0.iter().all(Self::is_constant) => Dynamic(Union::Array(Box::new(
|
|
||||||
x.0.iter()
|
|
||||||
.map(|v| v.get_constant_value().unwrap())
|
|
||||||
.collect(),
|
|
||||||
))),
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
|
||||||
Self::Map(x) if x.0.iter().all(|(_, v)| v.is_constant()) => {
|
|
||||||
Dynamic(Union::Map(Box::new(
|
|
||||||
x.0.iter()
|
|
||||||
.map(|(k, v)| (k.name.clone(), v.get_constant_value().unwrap()))
|
|
||||||
.collect(),
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => return None,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Is the expression a simple variable access?
|
|
||||||
pub(crate) fn get_variable_access(&self, non_qualified: bool) -> Option<&str> {
|
|
||||||
match self {
|
|
||||||
Self::Variable(x) if !non_qualified || x.1.is_none() => Some((x.0).name.as_str()),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the `Position` of the expression.
|
|
||||||
pub fn position(&self) -> Position {
|
|
||||||
match self {
|
|
||||||
Self::Expr(x) => x.position(),
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
|
||||||
Self::FloatConstant(x) => x.1,
|
|
||||||
|
|
||||||
Self::IntegerConstant(x) => x.1,
|
|
||||||
Self::CharConstant(x) => x.1,
|
|
||||||
Self::StringConstant(x) => x.pos,
|
|
||||||
Self::FnPointer(x) => x.pos,
|
|
||||||
Self::Array(x) => x.1,
|
|
||||||
Self::Map(x) => x.1,
|
|
||||||
Self::Property(x) => x.1,
|
|
||||||
Self::Stmt(x) => x.1,
|
|
||||||
Self::Variable(x) => (x.0).pos,
|
|
||||||
Self::FnCall(x) => (x.0).3,
|
|
||||||
|
|
||||||
Self::And(x) | Self::Or(x) | Self::In(x) => x.pos,
|
|
||||||
|
|
||||||
Self::True(pos) | Self::False(pos) | Self::Unit(pos) => *pos,
|
|
||||||
|
|
||||||
Self::Dot(x) | Self::Index(x) => x.lhs.position(),
|
|
||||||
|
|
||||||
Self::Custom(x) => x.pos,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Override the `Position` of the expression.
|
|
||||||
pub fn set_position(&mut self, new_pos: Position) -> &mut Self {
|
|
||||||
match self {
|
|
||||||
Self::Expr(x) => {
|
|
||||||
x.set_position(new_pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
|
||||||
Self::FloatConstant(x) => x.1 = new_pos,
|
|
||||||
|
|
||||||
Self::IntegerConstant(x) => x.1 = new_pos,
|
|
||||||
Self::CharConstant(x) => x.1 = new_pos,
|
|
||||||
Self::StringConstant(x) => x.pos = new_pos,
|
|
||||||
Self::FnPointer(x) => x.pos = new_pos,
|
|
||||||
Self::Array(x) => x.1 = new_pos,
|
|
||||||
Self::Map(x) => x.1 = new_pos,
|
|
||||||
Self::Variable(x) => (x.0).pos = new_pos,
|
|
||||||
Self::Property(x) => x.1 = new_pos,
|
|
||||||
Self::Stmt(x) => x.1 = new_pos,
|
|
||||||
Self::FnCall(x) => (x.0).3 = new_pos,
|
|
||||||
Self::And(x) | Self::Or(x) | Self::In(x) => x.pos = new_pos,
|
|
||||||
Self::True(pos) | Self::False(pos) | Self::Unit(pos) => *pos = new_pos,
|
|
||||||
Self::Dot(x) | Self::Index(x) => x.pos = new_pos,
|
|
||||||
Self::Custom(x) => x.pos = new_pos,
|
|
||||||
}
|
|
||||||
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Is the expression pure?
|
|
||||||
///
|
|
||||||
/// A pure expression has no side effects.
|
|
||||||
pub fn is_pure(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
Self::Expr(x) => x.is_pure(),
|
|
||||||
|
|
||||||
Self::Array(x) => x.0.iter().all(Self::is_pure),
|
|
||||||
|
|
||||||
Self::Index(x) | Self::And(x) | Self::Or(x) | Self::In(x) => {
|
|
||||||
x.lhs.is_pure() && x.rhs.is_pure()
|
|
||||||
}
|
|
||||||
|
|
||||||
Self::Stmt(x) => x.0.is_pure(),
|
|
||||||
|
|
||||||
Self::Variable(_) => true,
|
|
||||||
|
|
||||||
_ => self.is_constant(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Is the expression the unit `()` literal?
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn is_unit(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
Self::Unit(_) => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Is the expression a simple constant literal?
|
|
||||||
pub fn is_literal(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
Self::Expr(x) => x.is_literal(),
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
|
||||||
Self::FloatConstant(_) => true,
|
|
||||||
|
|
||||||
Self::IntegerConstant(_)
|
|
||||||
| Self::CharConstant(_)
|
|
||||||
| Self::StringConstant(_)
|
|
||||||
| Self::FnPointer(_)
|
|
||||||
| Self::True(_)
|
|
||||||
| Self::False(_)
|
|
||||||
| Self::Unit(_) => true,
|
|
||||||
|
|
||||||
// An array literal is literal if all items are literals
|
|
||||||
Self::Array(x) => x.0.iter().all(Self::is_literal),
|
|
||||||
|
|
||||||
// An map literal is literal if all items are literals
|
|
||||||
Self::Map(x) => x.0.iter().map(|(_, expr)| expr).all(Self::is_literal),
|
|
||||||
|
|
||||||
// Check in expression
|
|
||||||
Self::In(x) => match (&x.lhs, &x.rhs) {
|
|
||||||
(Self::StringConstant(_), Self::StringConstant(_))
|
|
||||||
| (Self::CharConstant(_), Self::StringConstant(_)) => true,
|
|
||||||
_ => false,
|
|
||||||
},
|
|
||||||
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Is the expression a constant?
|
|
||||||
pub fn is_constant(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
Self::Expr(x) => x.is_constant(),
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
|
||||||
Self::FloatConstant(_) => true,
|
|
||||||
|
|
||||||
Self::IntegerConstant(_)
|
|
||||||
| Self::CharConstant(_)
|
|
||||||
| Self::StringConstant(_)
|
|
||||||
| Self::FnPointer(_)
|
|
||||||
| Self::True(_)
|
|
||||||
| Self::False(_)
|
|
||||||
| Self::Unit(_) => true,
|
|
||||||
|
|
||||||
// An array literal is constant if all items are constant
|
|
||||||
Self::Array(x) => x.0.iter().all(Self::is_constant),
|
|
||||||
|
|
||||||
// An map literal is constant if all items are constant
|
|
||||||
Self::Map(x) => x.0.iter().map(|(_, expr)| expr).all(Self::is_constant),
|
|
||||||
|
|
||||||
// Check in expression
|
|
||||||
Self::In(x) => match (&x.lhs, &x.rhs) {
|
|
||||||
(Self::StringConstant(_), Self::StringConstant(_))
|
|
||||||
| (Self::CharConstant(_), Self::StringConstant(_)) => true,
|
|
||||||
_ => false,
|
|
||||||
},
|
|
||||||
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Is a particular token allowed as a postfix operator to this expression?
|
|
||||||
pub fn is_valid_postfix(&self, token: &Token) -> bool {
|
|
||||||
match self {
|
|
||||||
Self::Expr(x) => x.is_valid_postfix(token),
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
|
||||||
Self::FloatConstant(_) => false,
|
|
||||||
|
|
||||||
Self::IntegerConstant(_)
|
|
||||||
| Self::CharConstant(_)
|
|
||||||
| Self::FnPointer(_)
|
|
||||||
| Self::In(_)
|
|
||||||
| Self::And(_)
|
|
||||||
| Self::Or(_)
|
|
||||||
| Self::True(_)
|
|
||||||
| Self::False(_)
|
|
||||||
| Self::Unit(_) => false,
|
|
||||||
|
|
||||||
Self::StringConstant(_)
|
|
||||||
| Self::Stmt(_)
|
|
||||||
| Self::FnCall(_)
|
|
||||||
| Self::Dot(_)
|
|
||||||
| Self::Index(_)
|
|
||||||
| Self::Array(_)
|
|
||||||
| Self::Map(_) => match token {
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
|
||||||
Token::LeftBracket => true,
|
|
||||||
_ => false,
|
|
||||||
},
|
|
||||||
|
|
||||||
Self::Variable(_) => match token {
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
|
||||||
Token::LeftBracket => true,
|
|
||||||
Token::LeftParen => true,
|
|
||||||
Token::Bang => true,
|
|
||||||
Token::DoubleColon => true,
|
|
||||||
_ => false,
|
|
||||||
},
|
|
||||||
|
|
||||||
Self::Property(_) => match token {
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
|
||||||
Token::LeftBracket => true,
|
|
||||||
Token::LeftParen => true,
|
|
||||||
_ => false,
|
|
||||||
},
|
|
||||||
|
|
||||||
Self::Custom(_) => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Convert a `Variable` into a `Property`. All other variants are untouched.
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
|
||||||
#[inline]
|
|
||||||
pub(crate) fn into_property(self) -> Self {
|
|
||||||
match self {
|
|
||||||
Self::Variable(x) if x.1.is_none() => {
|
|
||||||
let Ident { name, pos } = x.0;
|
|
||||||
let getter = make_getter(&name);
|
|
||||||
let setter = make_setter(&name);
|
|
||||||
Self::Property(Box::new(((name.into(), getter, setter), pos)))
|
|
||||||
}
|
|
||||||
_ => self,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Consume a particular token, checking that it is the expected one.
|
/// Consume a particular token, checking that it is the expected one.
|
||||||
fn eat_token(input: &mut TokenStream, token: Token) -> Position {
|
fn eat_token(input: &mut TokenStream, token: Token) -> Position {
|
||||||
let (t, pos) = input.next().unwrap();
|
let (t, pos) = input.next().unwrap();
|
||||||
@ -1737,10 +963,9 @@ fn parse_unary(
|
|||||||
.map(|i| Expr::IntegerConstant(Box::new((i, pos))))
|
.map(|i| Expr::IntegerConstant(Box::new((i, pos))))
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
return Some(Expr::FloatConstant(Box::new(FloatWrapper(
|
return Some(Expr::FloatConstant(Box::new(
|
||||||
-(x.0 as FLOAT),
|
-Into::<FloatWrapper>::into(*x),
|
||||||
pos,
|
)));
|
||||||
))));
|
|
||||||
#[cfg(feature = "no_float")]
|
#[cfg(feature = "no_float")]
|
||||||
return None;
|
return None;
|
||||||
})
|
})
|
||||||
@ -1749,9 +974,7 @@ fn parse_unary(
|
|||||||
|
|
||||||
// Negative float
|
// Negative float
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
Expr::FloatConstant(x) => {
|
Expr::FloatConstant(x) => Ok(Expr::FloatConstant(Box::new(-(*x)))),
|
||||||
Ok(Expr::FloatConstant(Box::new(FloatWrapper(-x.0, x.1))))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Call negative function
|
// Call negative function
|
||||||
expr => {
|
expr => {
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
//! Module defining macros for developing _plugins_.
|
//! Module defining macros for developing _plugins_.
|
||||||
|
|
||||||
|
pub use crate::ast::FnAccess;
|
||||||
pub use crate::dynamic::Dynamic;
|
pub use crate::dynamic::Dynamic;
|
||||||
pub use crate::engine::Engine;
|
pub use crate::engine::Engine;
|
||||||
pub use crate::fn_native::{CallableFunction, FnCallArgs, NativeCallContext};
|
pub use crate::fn_native::{CallableFunction, FnCallArgs, NativeCallContext};
|
||||||
pub use crate::fn_register::{RegisterFn, RegisterResultFn};
|
pub use crate::fn_register::{RegisterFn, RegisterResultFn};
|
||||||
pub use crate::module::Module;
|
pub use crate::module::Module;
|
||||||
pub use crate::parser::FnAccess;
|
|
||||||
pub use crate::result::EvalAltResult;
|
pub use crate::result::EvalAltResult;
|
||||||
pub use crate::utils::ImmutableString;
|
pub use crate::utils::ImmutableString;
|
||||||
|
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
use crate::dynamic::Dynamic;
|
use crate::dynamic::Dynamic;
|
||||||
use crate::parse_error::ParseErrorType;
|
use crate::parse_error::ParseErrorType;
|
||||||
use crate::parser::INT;
|
|
||||||
use crate::token::Position;
|
use crate::token::Position;
|
||||||
use crate::utils::ImmutableString;
|
use crate::utils::ImmutableString;
|
||||||
|
use crate::INT;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
use crate::engine::is_anonymous_fn;
|
use crate::engine::is_anonymous_fn;
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
//! Module that defines the `Scope` type representing a function call-stack scope.
|
//! Module that defines the `Scope` type representing a function call-stack scope.
|
||||||
|
|
||||||
|
use crate::ast::Expr;
|
||||||
use crate::dynamic::{Dynamic, Variant};
|
use crate::dynamic::{Dynamic, Variant};
|
||||||
use crate::parser::{map_dynamic_to_expr, Expr};
|
use crate::parser::map_dynamic_to_expr;
|
||||||
use crate::token::Position;
|
use crate::token::Position;
|
||||||
|
|
||||||
use crate::stdlib::{borrow::Cow, boxed::Box, iter, string::String, vec::Vec};
|
use crate::stdlib::{borrow::Cow, boxed::Box, iter, string::String, vec::Vec};
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
//! Module implementing custom syntax for `Engine`.
|
//! Module implementing custom syntax for `Engine`.
|
||||||
|
|
||||||
|
use crate::ast::Expr;
|
||||||
use crate::dynamic::Dynamic;
|
use crate::dynamic::Dynamic;
|
||||||
use crate::engine::{Engine, EvalContext, MARKER_BLOCK, MARKER_EXPR, MARKER_IDENT};
|
use crate::engine::{Engine, EvalContext, MARKER_BLOCK, MARKER_EXPR, MARKER_IDENT};
|
||||||
use crate::fn_native::{SendSync, Shared};
|
use crate::fn_native::{SendSync, Shared};
|
||||||
use crate::parse_error::{LexError, ParseError};
|
use crate::parse_error::{LexError, ParseError};
|
||||||
use crate::parser::Expr;
|
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::token::{is_valid_identifier, Position, Token};
|
use crate::token::{is_valid_identifier, Position, Token};
|
||||||
use crate::utils::ImmutableString;
|
use crate::utils::ImmutableString;
|
||||||
|
@ -9,11 +9,11 @@ use crate::engine::{
|
|||||||
use crate::engine::KEYWORD_IS_SHARED;
|
use crate::engine::KEYWORD_IS_SHARED;
|
||||||
|
|
||||||
use crate::parse_error::LexError;
|
use crate::parse_error::LexError;
|
||||||
use crate::parser::INT;
|
|
||||||
use crate::StaticVec;
|
use crate::StaticVec;
|
||||||
|
use crate::INT;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
use crate::parser::FLOAT;
|
use crate::FLOAT;
|
||||||
|
|
||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
|
10
src/utils.rs
10
src/utils.rs
@ -42,14 +42,6 @@ impl Hasher for StraightHasher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StraightHasher {
|
|
||||||
/// Create a `StraightHasher`.
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A hash builder for `StraightHasher`.
|
/// A hash builder for `StraightHasher`.
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Default)]
|
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Default)]
|
||||||
pub struct StraightHasherBuilder;
|
pub struct StraightHasherBuilder;
|
||||||
@ -59,7 +51,7 @@ impl BuildHasher for StraightHasherBuilder {
|
|||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn build_hasher(&self) -> Self::Hasher {
|
fn build_hasher(&self) -> Self::Hasher {
|
||||||
StraightHasher::new()
|
Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user