Mark simple functions const.

This commit is contained in:
Stephen Chung 2021-06-28 18:06:05 +08:00
parent 0c99165007
commit e40e81ac1a
16 changed files with 243 additions and 210 deletions

View File

@ -911,7 +911,7 @@ impl StmtBlock {
/// Get the position of this statements block. /// Get the position of this statements block.
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn position(&self) -> Position { pub const fn position(&self) -> Position {
self.1 self.1
} }
/// Get the statements of this statements block. /// Get the statements of this statements block.
@ -1044,7 +1044,7 @@ impl Stmt {
/// Is this statement [`Noop`][Stmt::Noop]? /// Is this statement [`Noop`][Stmt::Noop]?
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn is_noop(&self) -> bool { pub const fn is_noop(&self) -> bool {
match self { match self {
Self::Noop(_) => true, Self::Noop(_) => true,
_ => false, _ => false,
@ -1117,7 +1117,7 @@ impl Stmt {
} }
/// Does this statement return a value? /// Does this statement return a value?
#[must_use] #[must_use]
pub fn returns_value(&self) -> bool { pub const fn returns_value(&self) -> bool {
match self { match self {
Self::If(_, _, _) Self::If(_, _, _)
| Self::Switch(_, _, _) | Self::Switch(_, _, _)
@ -1142,12 +1142,12 @@ impl Stmt {
Self::Import(_, _, _) | Self::Export(_, _) => false, Self::Import(_, _, _) | Self::Export(_, _) => false,
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
Self::Share(_) => unreachable!("Stmt::Share should not be parsed"), Self::Share(_) => false,
} }
} }
/// Is this statement self-terminated (i.e. no need for a semicolon terminator)? /// Is this statement self-terminated (i.e. no need for a semicolon terminator)?
#[must_use] #[must_use]
pub fn is_self_terminated(&self) -> bool { pub const fn is_self_terminated(&self) -> bool {
match self { match self {
Self::If(_, _, _) Self::If(_, _, _)
| Self::Switch(_, _, _) | Self::Switch(_, _, _)
@ -1173,7 +1173,7 @@ impl Stmt {
Self::Import(_, _, _) | Self::Export(_, _) => false, Self::Import(_, _, _) | Self::Export(_, _) => false,
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
Self::Share(_) => unreachable!("Stmt::Share should not be parsed"), Self::Share(_) => false,
} }
} }
/// Is this statement _pure_? /// Is this statement _pure_?
@ -1247,7 +1247,7 @@ impl Stmt {
/// All statements following this statement will essentially be dead code. /// All statements following this statement will essentially be dead code.
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn is_control_flow_break(&self) -> bool { pub const fn is_control_flow_break(&self) -> bool {
match self { match self {
Self::Return(_, _, _) | Self::Break(_) | Self::Continue(_) => true, Self::Return(_, _, _) | Self::Break(_) | Self::Continue(_) => true,
_ => false, _ => false,
@ -1512,7 +1512,7 @@ impl FnCallHashes {
/// Create a [`FnCallHashes`] with only the native Rust hash. /// Create a [`FnCallHashes`] with only the native Rust hash.
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn from_native(hash: u64) -> Self { pub const fn from_native(hash: u64) -> Self {
Self { Self {
script: None, script: None,
native: hash, native: hash,
@ -1521,7 +1521,7 @@ impl FnCallHashes {
/// Create a [`FnCallHashes`] with both native Rust and script function hashes set to the same value. /// Create a [`FnCallHashes`] with both native Rust and script function hashes set to the same value.
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn from_script(hash: u64) -> Self { pub const fn from_script(hash: u64) -> Self {
Self { Self {
script: Some(hash), script: Some(hash),
native: hash, native: hash,
@ -1530,7 +1530,7 @@ impl FnCallHashes {
/// Create a [`FnCallHashes`] with both native Rust and script function hashes. /// Create a [`FnCallHashes`] with both native Rust and script function hashes.
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn from_script_and_native(script: u64, native: u64) -> Self { pub const fn from_script_and_native(script: u64, native: u64) -> Self {
Self { Self {
script: Some(script), script: Some(script),
native, native,
@ -1539,7 +1539,7 @@ impl FnCallHashes {
/// Is this [`FnCallHashes`] native Rust only? /// Is this [`FnCallHashes`] native Rust only?
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn is_native_only(&self) -> bool { pub const fn is_native_only(&self) -> bool {
self.script.is_none() self.script.is_none()
} }
} }
@ -1570,7 +1570,7 @@ impl FnCallExpr {
/// Does this function call contain a qualified namespace? /// Does this function call contain a qualified namespace?
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn is_qualified(&self) -> bool { pub const fn is_qualified(&self) -> bool {
self.namespace.is_some() self.namespace.is_some()
} }
/// Convert this into a [`FnCall`][Expr::FnCall]. /// Convert this into a [`FnCall`][Expr::FnCall].
@ -1683,6 +1683,7 @@ impl<F: Float> FloatWrapper<F> {
/// Minimum floating-point number for natural display before switching to scientific notation. /// Minimum floating-point number for natural display before switching to scientific notation.
pub const MIN_NATURAL_FLOAT_FOR_DISPLAY: f32 = 0.0000000000001; pub const MIN_NATURAL_FLOAT_FOR_DISPLAY: f32 = 0.0000000000001;
/// Create a new [`FloatWrapper`].
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn new(value: F) -> Self { pub fn new(value: F) -> Self {
@ -1692,6 +1693,7 @@ impl<F: Float> FloatWrapper<F> {
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
impl FloatWrapper<FLOAT> { impl FloatWrapper<FLOAT> {
/// Create a new [`FloatWrapper`].
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub(crate) const fn const_new(value: FLOAT) -> Self { pub(crate) const fn const_new(value: FLOAT) -> Self {
@ -1928,7 +1930,7 @@ impl Expr {
/// Is the expression a simple variable access? /// Is the expression a simple variable access?
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub(crate) fn is_variable_access(&self, non_qualified: bool) -> bool { pub(crate) const fn is_variable_access(&self, non_qualified: bool) -> bool {
match self { match self {
Self::Variable(_, _, x) => !non_qualified || x.1.is_none(), Self::Variable(_, _, x) => !non_qualified || x.1.is_none(),
_ => false, _ => false,
@ -2038,7 +2040,7 @@ impl Expr {
/// Is the expression the unit `()` literal? /// Is the expression the unit `()` literal?
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn is_unit(&self) -> bool { pub const fn is_unit(&self) -> bool {
match self { match self {
Self::Unit(_) => true, Self::Unit(_) => true,
_ => false, _ => false,
@ -2070,7 +2072,7 @@ impl Expr {
/// Is a particular [token][Token] allowed as a postfix operator to this expression? /// Is a particular [token][Token] allowed as a postfix operator to this expression?
#[inline] #[inline]
#[must_use] #[must_use]
pub fn is_valid_postfix(&self, token: &Token) -> bool { pub const fn is_valid_postfix(&self, token: &Token) -> bool {
match token { match token {
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
Token::Period => return true, Token::Period => return true,
@ -2120,7 +2122,7 @@ impl Expr {
Self::Custom(_, _) => false, Self::Custom(_, _) => false,
Self::Stack(_, _) => unreachable!("Expr::Stack should not occur naturally"), Self::Stack(_, _) => false,
} }
} }
/// Recursively walk this expression. /// Recursively walk this expression.

View File

@ -14,14 +14,21 @@ use std::any::TypeId;
#[cfg(feature = "no_std")] #[cfg(feature = "no_std")]
use std::prelude::v1::*; use std::prelude::v1::*;
pub const MARKER_EXPR: &str = "$expr$"; /// Special marker for matching an expression.
pub const MARKER_BLOCK: &str = "$block$"; pub const CUSTOM_SYNTAX_MARKER_EXPR: &str = "$expr$";
pub const MARKER_IDENT: &str = "$ident$"; /// Special marker for matching a statements block.
pub const MARKER_STRING: &str = "$string$"; pub const CUSTOM_SYNTAX_MARKER_BLOCK: &str = "$block$";
pub const MARKER_INT: &str = "$int$"; /// Special marker for matching an identifier.
pub const CUSTOM_SYNTAX_MARKER_IDENT: &str = "$ident$";
/// Special marker for matching a string literal.
pub const CUSTOM_SYNTAX_MARKER_STRING: &str = "$string$";
/// Special marker for matching an integer number.
pub const CUSTOM_SYNTAX_MARKER_INT: &str = "$int$";
/// Special marker for matching a floating-point number.
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
pub const MARKER_FLOAT: &str = "$float$"; pub const CUSTOM_SYNTAX_MARKER_FLOAT: &str = "$float$";
pub const MARKER_BOOL: &str = "$bool$"; /// Special marker for matching a boolean value.
pub const CUSTOM_SYNTAX_MARKER_BOOL: &str = "$bool$";
/// A general expression evaluation trait object. /// A general expression evaluation trait object.
#[cfg(not(feature = "sync"))] #[cfg(not(feature = "sync"))]
@ -185,7 +192,7 @@ impl Engine {
for s in keywords { for s in keywords {
let s = s.as_ref().trim(); let s = s.as_ref().trim();
// skip empty keywords // Skip empty keywords
if s.is_empty() { if s.is_empty() {
continue; continue;
} }
@ -194,15 +201,19 @@ impl Engine {
let seg = match s { let seg = match s {
// Markers not in first position // Markers not in first position
MARKER_IDENT | MARKER_EXPR | MARKER_BLOCK | MARKER_BOOL | MARKER_INT CUSTOM_SYNTAX_MARKER_IDENT
| MARKER_STRING | CUSTOM_SYNTAX_MARKER_EXPR
| CUSTOM_SYNTAX_MARKER_BLOCK
| CUSTOM_SYNTAX_MARKER_BOOL
| CUSTOM_SYNTAX_MARKER_INT
| CUSTOM_SYNTAX_MARKER_STRING
if !segments.is_empty() => if !segments.is_empty() =>
{ {
s.into() s.into()
} }
// Markers not in first position // Markers not in first position
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
MARKER_FLOAT if !segments.is_empty() => s.into(), CUSTOM_SYNTAX_MARKER_FLOAT if !segments.is_empty() => s.into(),
// Standard or reserved keyword/symbol not in first position // Standard or reserved keyword/symbol not in first position
s if !segments.is_empty() && token.is_some() => { s if !segments.is_empty() && token.is_some() => {
// Make it a custom keyword/symbol if it is disabled or reserved // Make it a custom keyword/symbol if it is disabled or reserved

View File

@ -33,6 +33,7 @@ use fmt::Debug;
#[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
use instant::Instant; use instant::Instant;
/// The message: never fails because the type was checked
const CHECKED: &str = "never fails because the type was checked"; const CHECKED: &str = "never fails because the type was checked";
mod private { mod private {
@ -164,7 +165,7 @@ pub type Tag = i32;
pub type Tag = i16; pub type Tag = i16;
/// Default tag value for [`Dynamic`]. /// Default tag value for [`Dynamic`].
const DEFAULT_TAG: Tag = 0; const DEFAULT_TAG_VALUE: Tag = 0;
/// Dynamic type containing any value. /// Dynamic type containing any value.
pub struct Dynamic(pub(crate) Union); pub struct Dynamic(pub(crate) Union);
@ -711,8 +712,6 @@ impl fmt::Debug for Dynamic {
let _value_any = (***value).as_any(); let _value_any = (***value).as_any();
let _type_id = _value_any.type_id(); let _type_id = _value_any.type_id();
const CHECKED: &str = "never fails because the type was checked";
#[cfg(not(feature = "only_i32"))] #[cfg(not(feature = "only_i32"))]
#[cfg(not(feature = "only_i64"))] #[cfg(not(feature = "only_i64"))]
if _type_id == TypeId::of::<u8>() { if _type_id == TypeId::of::<u8>() {
@ -819,28 +818,28 @@ impl Default for Dynamic {
impl Dynamic { impl Dynamic {
/// A [`Dynamic`] containing a `()`. /// A [`Dynamic`] containing a `()`.
pub const UNIT: Dynamic = Self(Union::Unit((), DEFAULT_TAG, ReadWrite)); pub const UNIT: Dynamic = Self(Union::Unit((), DEFAULT_TAG_VALUE, ReadWrite));
/// A [`Dynamic`] containing a `true`. /// A [`Dynamic`] containing a `true`.
pub const TRUE: Dynamic = Self(Union::Bool(true, DEFAULT_TAG, ReadWrite)); pub const TRUE: Dynamic = Self(Union::Bool(true, DEFAULT_TAG_VALUE, ReadWrite));
/// A [`Dynamic`] containing a [`false`]. /// A [`Dynamic`] containing a [`false`].
pub const FALSE: Dynamic = Self(Union::Bool(false, DEFAULT_TAG, ReadWrite)); pub const FALSE: Dynamic = Self(Union::Bool(false, DEFAULT_TAG_VALUE, ReadWrite));
/// A [`Dynamic`] containing the integer zero. /// A [`Dynamic`] containing the integer zero.
pub const ZERO: Dynamic = Self(Union::Int(0, DEFAULT_TAG, ReadWrite)); pub const ZERO: Dynamic = Self(Union::Int(0, DEFAULT_TAG_VALUE, ReadWrite));
/// A [`Dynamic`] containing the integer one. /// A [`Dynamic`] containing the integer one.
pub const ONE: Dynamic = Self(Union::Int(1, DEFAULT_TAG, ReadWrite)); pub const ONE: Dynamic = Self(Union::Int(1, DEFAULT_TAG_VALUE, ReadWrite));
/// A [`Dynamic`] containing the integer two. /// A [`Dynamic`] containing the integer two.
pub const TWO: Dynamic = Self(Union::Int(2, DEFAULT_TAG, ReadWrite)); pub const TWO: Dynamic = Self(Union::Int(2, DEFAULT_TAG_VALUE, ReadWrite));
/// A [`Dynamic`] containing the integer ten. /// A [`Dynamic`] containing the integer ten.
pub const TEN: Dynamic = Self(Union::Int(10, DEFAULT_TAG, ReadWrite)); pub const TEN: Dynamic = Self(Union::Int(10, DEFAULT_TAG_VALUE, ReadWrite));
/// A [`Dynamic`] containing the integer negative one. /// A [`Dynamic`] containing the integer negative one.
pub const NEGATIVE_ONE: Dynamic = Self(Union::Int(-1, DEFAULT_TAG, ReadWrite)); pub const NEGATIVE_ONE: Dynamic = Self(Union::Int(-1, DEFAULT_TAG_VALUE, ReadWrite));
/// A [`Dynamic`] containing `0.0`. /// A [`Dynamic`] containing `0.0`.
/// ///
/// Not available under `no_float`. /// Not available under `no_float`.
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
pub const FLOAT_ZERO: Dynamic = Self(Union::Float( pub const FLOAT_ZERO: Dynamic = Self(Union::Float(
FloatWrapper::const_new(0.0), FloatWrapper::const_new(0.0),
DEFAULT_TAG, DEFAULT_TAG_VALUE,
ReadWrite, ReadWrite,
)); ));
/// A [`Dynamic`] containing `1.0`. /// A [`Dynamic`] containing `1.0`.
@ -849,7 +848,7 @@ impl Dynamic {
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
pub const FLOAT_ONE: Dynamic = Self(Union::Float( pub const FLOAT_ONE: Dynamic = Self(Union::Float(
FloatWrapper::const_new(1.0), FloatWrapper::const_new(1.0),
DEFAULT_TAG, DEFAULT_TAG_VALUE,
ReadWrite, ReadWrite,
)); ));
/// A [`Dynamic`] containing `2.0`. /// A [`Dynamic`] containing `2.0`.
@ -858,7 +857,7 @@ impl Dynamic {
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
pub const FLOAT_TWO: Dynamic = Self(Union::Float( pub const FLOAT_TWO: Dynamic = Self(Union::Float(
FloatWrapper::const_new(2.0), FloatWrapper::const_new(2.0),
DEFAULT_TAG, DEFAULT_TAG_VALUE,
ReadWrite, ReadWrite,
)); ));
/// A [`Dynamic`] containing `10.0`. /// A [`Dynamic`] containing `10.0`.
@ -867,7 +866,7 @@ impl Dynamic {
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
pub const FLOAT_TEN: Dynamic = Self(Union::Float( pub const FLOAT_TEN: Dynamic = Self(Union::Float(
FloatWrapper::const_new(10.0), FloatWrapper::const_new(10.0),
DEFAULT_TAG, DEFAULT_TAG_VALUE,
ReadWrite, ReadWrite,
)); ));
/// A [`Dynamic`] containing the `-1.0`. /// A [`Dynamic`] containing the `-1.0`.
@ -876,7 +875,7 @@ impl Dynamic {
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
pub const FLOAT_NEGATIVE_ONE: Dynamic = Self(Union::Float( pub const FLOAT_NEGATIVE_ONE: Dynamic = Self(Union::Float(
FloatWrapper::const_new(-1.0), FloatWrapper::const_new(-1.0),
DEFAULT_TAG, DEFAULT_TAG_VALUE,
ReadWrite, ReadWrite,
)); ));
@ -1043,8 +1042,6 @@ impl Dynamic {
pub fn from<T: Variant + Clone>(mut value: T) -> Self { pub fn from<T: Variant + Clone>(mut value: T) -> Self {
// Coded this way in order to maximally leverage potentials for dead-code removal. // Coded this way in order to maximally leverage potentials for dead-code removal.
const CHECKED: &str = "never fails because the type was checked";
if TypeId::of::<T>() == TypeId::of::<Dynamic>() { if TypeId::of::<T>() == TypeId::of::<Dynamic>() {
return unsafe_try_cast::<_, Dynamic>(value).ok().expect(CHECKED); return unsafe_try_cast::<_, Dynamic>(value).ok().expect(CHECKED);
} }
@ -1125,7 +1122,7 @@ impl Dynamic {
Self(Union::Variant( Self(Union::Variant(
Box::new(Box::new(value)), Box::new(Box::new(value)),
DEFAULT_TAG, DEFAULT_TAG_VALUE,
ReadWrite, ReadWrite,
)) ))
} }
@ -1153,7 +1150,7 @@ impl Dynamic {
Union::Shared(_, _, _) => self, Union::Shared(_, _, _) => self,
_ => Self(Union::Shared( _ => Self(Union::Shared(
crate::Locked::new(self).into(), crate::Locked::new(self).into(),
DEFAULT_TAG, DEFAULT_TAG_VALUE,
_access, _access,
)), )),
} }
@ -1857,33 +1854,33 @@ impl Dynamic {
impl From<()> for Dynamic { impl From<()> for Dynamic {
#[inline(always)] #[inline(always)]
fn from(value: ()) -> Self { fn from(value: ()) -> Self {
Self(Union::Unit(value, DEFAULT_TAG, ReadWrite)) Self(Union::Unit(value, DEFAULT_TAG_VALUE, ReadWrite))
} }
} }
impl From<bool> for Dynamic { impl From<bool> for Dynamic {
#[inline(always)] #[inline(always)]
fn from(value: bool) -> Self { fn from(value: bool) -> Self {
Self(Union::Bool(value, DEFAULT_TAG, ReadWrite)) Self(Union::Bool(value, DEFAULT_TAG_VALUE, ReadWrite))
} }
} }
impl From<INT> for Dynamic { impl From<INT> for Dynamic {
#[inline(always)] #[inline(always)]
fn from(value: INT) -> Self { fn from(value: INT) -> Self {
Self(Union::Int(value, DEFAULT_TAG, ReadWrite)) Self(Union::Int(value, DEFAULT_TAG_VALUE, ReadWrite))
} }
} }
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
impl From<FLOAT> for Dynamic { impl From<FLOAT> for Dynamic {
#[inline(always)] #[inline(always)]
fn from(value: FLOAT) -> Self { fn from(value: FLOAT) -> Self {
Self(Union::Float(value.into(), DEFAULT_TAG, ReadWrite)) Self(Union::Float(value.into(), DEFAULT_TAG_VALUE, ReadWrite))
} }
} }
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
impl From<FloatWrapper<FLOAT>> for Dynamic { impl From<FloatWrapper<FLOAT>> for Dynamic {
#[inline(always)] #[inline(always)]
fn from(value: FloatWrapper<FLOAT>) -> Self { fn from(value: FloatWrapper<FLOAT>) -> Self {
Self(Union::Float(value, DEFAULT_TAG, ReadWrite)) Self(Union::Float(value, DEFAULT_TAG_VALUE, ReadWrite))
} }
} }
#[cfg(feature = "decimal")] #[cfg(feature = "decimal")]
@ -1900,13 +1897,13 @@ impl From<Decimal> for Dynamic {
impl From<char> for Dynamic { impl From<char> for Dynamic {
#[inline(always)] #[inline(always)]
fn from(value: char) -> Self { fn from(value: char) -> Self {
Self(Union::Char(value, DEFAULT_TAG, ReadWrite)) Self(Union::Char(value, DEFAULT_TAG_VALUE, ReadWrite))
} }
} }
impl<S: Into<ImmutableString>> From<S> for Dynamic { impl<S: Into<ImmutableString>> From<S> for Dynamic {
#[inline(always)] #[inline(always)]
fn from(value: S) -> Self { fn from(value: S) -> Self {
Self(Union::Str(value.into(), DEFAULT_TAG, ReadWrite)) Self(Union::Str(value.into(), DEFAULT_TAG_VALUE, ReadWrite))
} }
} }
impl From<&ImmutableString> for Dynamic { impl From<&ImmutableString> for Dynamic {
@ -1927,7 +1924,7 @@ impl Dynamic {
/// Create a [`Dynamic`] from an [`Array`]. /// Create a [`Dynamic`] from an [`Array`].
#[inline(always)] #[inline(always)]
pub(crate) fn from_array(array: Array) -> Self { pub(crate) fn from_array(array: Array) -> Self {
Self(Union::Array(Box::new(array), DEFAULT_TAG, ReadWrite)) Self(Union::Array(Box::new(array), DEFAULT_TAG_VALUE, ReadWrite))
} }
} }
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
@ -1936,7 +1933,7 @@ impl<T: Variant + Clone> From<Vec<T>> for Dynamic {
fn from(value: Vec<T>) -> Self { fn from(value: Vec<T>) -> Self {
Self(Union::Array( Self(Union::Array(
Box::new(value.into_iter().map(Dynamic::from).collect()), Box::new(value.into_iter().map(Dynamic::from).collect()),
DEFAULT_TAG, DEFAULT_TAG_VALUE,
ReadWrite, ReadWrite,
)) ))
} }
@ -1947,7 +1944,7 @@ impl<T: Variant + Clone> From<&[T]> for Dynamic {
fn from(value: &[T]) -> Self { fn from(value: &[T]) -> Self {
Self(Union::Array( Self(Union::Array(
Box::new(value.iter().cloned().map(Dynamic::from).collect()), Box::new(value.iter().cloned().map(Dynamic::from).collect()),
DEFAULT_TAG, DEFAULT_TAG_VALUE,
ReadWrite, ReadWrite,
)) ))
} }
@ -1958,7 +1955,7 @@ impl<T: Variant + Clone> std::iter::FromIterator<T> for Dynamic {
fn from_iter<X: IntoIterator<Item = T>>(iter: X) -> Self { fn from_iter<X: IntoIterator<Item = T>>(iter: X) -> Self {
Self(Union::Array( Self(Union::Array(
Box::new(iter.into_iter().map(Dynamic::from).collect()), Box::new(iter.into_iter().map(Dynamic::from).collect()),
DEFAULT_TAG, DEFAULT_TAG_VALUE,
ReadWrite, ReadWrite,
)) ))
} }
@ -1968,7 +1965,7 @@ impl Dynamic {
/// Create a [`Dynamic`] from a [`Map`]. /// Create a [`Dynamic`] from a [`Map`].
#[inline(always)] #[inline(always)]
pub(crate) fn from_map(map: Map) -> Self { pub(crate) fn from_map(map: Map) -> Self {
Self(Union::Map(Box::new(map), DEFAULT_TAG, ReadWrite)) Self(Union::Map(Box::new(map), DEFAULT_TAG_VALUE, ReadWrite))
} }
} }
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
@ -1985,7 +1982,7 @@ impl<K: Into<crate::Identifier>, T: Variant + Clone> From<std::collections::Hash
.map(|(k, v)| (k.into(), Dynamic::from(v))) .map(|(k, v)| (k.into(), Dynamic::from(v)))
.collect(), .collect(),
), ),
DEFAULT_TAG, DEFAULT_TAG_VALUE,
ReadWrite, ReadWrite,
)) ))
} }
@ -2003,7 +2000,7 @@ impl<K: Into<crate::Identifier>, T: Variant + Clone> From<std::collections::BTre
.map(|(k, v)| (k.into(), Dynamic::from(v))) .map(|(k, v)| (k.into(), Dynamic::from(v)))
.collect(), .collect(),
), ),
DEFAULT_TAG, DEFAULT_TAG_VALUE,
ReadWrite, ReadWrite,
)) ))
} }
@ -2011,26 +2008,30 @@ impl<K: Into<crate::Identifier>, T: Variant + Clone> From<std::collections::BTre
impl From<FnPtr> for Dynamic { impl From<FnPtr> for Dynamic {
#[inline(always)] #[inline(always)]
fn from(value: FnPtr) -> Self { fn from(value: FnPtr) -> Self {
Self(Union::FnPtr(Box::new(value), DEFAULT_TAG, ReadWrite)) Self(Union::FnPtr(Box::new(value), DEFAULT_TAG_VALUE, ReadWrite))
} }
} }
impl From<Box<FnPtr>> for Dynamic { impl From<Box<FnPtr>> for Dynamic {
#[inline(always)] #[inline(always)]
fn from(value: Box<FnPtr>) -> Self { fn from(value: Box<FnPtr>) -> Self {
Self(Union::FnPtr(value, DEFAULT_TAG, ReadWrite)) Self(Union::FnPtr(value, DEFAULT_TAG_VALUE, ReadWrite))
} }
} }
#[cfg(not(feature = "no_std"))] #[cfg(not(feature = "no_std"))]
impl From<Instant> for Dynamic { impl From<Instant> for Dynamic {
#[inline(always)] #[inline(always)]
fn from(value: Instant) -> Self { fn from(value: Instant) -> Self {
Self(Union::TimeStamp(Box::new(value), DEFAULT_TAG, ReadWrite)) Self(Union::TimeStamp(
Box::new(value),
DEFAULT_TAG_VALUE,
ReadWrite,
))
} }
} }
#[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "no_closure"))]
impl From<crate::Shared<crate::Locked<Dynamic>>> for Dynamic { impl From<crate::Shared<crate::Locked<Dynamic>>> for Dynamic {
#[inline(always)] #[inline(always)]
fn from(value: crate::Shared<crate::Locked<Self>>) -> Self { fn from(value: crate::Shared<crate::Locked<Self>>) -> Self {
Self(Union::Shared(value.into(), DEFAULT_TAG, ReadWrite)) Self(Union::Shared(value.into(), DEFAULT_TAG_VALUE, ReadWrite))
} }
} }

View File

@ -2064,7 +2064,12 @@ impl Engine {
.lib() .lib()
.iter_fn() .iter_fn()
.filter(|f| f.func.is_script()) .filter(|f| f.func.is_script())
.map(|f| f.func.get_fn_def().clone()) .map(|f| {
f.func
.get_script_fn_def()
.expect("never fails because the function is scripted")
.clone()
})
.collect(); .collect();
#[cfg(feature = "no_function")] #[cfg(feature = "no_function")]

View File

@ -50,7 +50,7 @@ impl Engine {
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn max_call_levels(&self) -> usize { pub const fn max_call_levels(&self) -> usize {
self.limits.max_call_stack_depth self.limits.max_call_stack_depth
} }
/// Set the maximum number of operations allowed for a script to run to avoid /// Set the maximum number of operations allowed for a script to run to avoid
@ -69,8 +69,12 @@ impl Engine {
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn max_operations(&self) -> u64 { pub const fn max_operations(&self) -> u64 {
self.limits.max_operations.map_or(0, NonZeroU64::get) if let Some(n) = self.limits.max_operations {
n.get()
} else {
0
}
} }
/// Set the maximum number of imported [modules][crate::Module] allowed for a script. /// Set the maximum number of imported [modules][crate::Module] allowed for a script.
/// ///
@ -89,7 +93,7 @@ impl Engine {
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn max_modules(&self) -> usize { pub const fn max_modules(&self) -> usize {
self.limits.max_modules self.limits.max_modules
} }
/// Set the depth limits for expressions (0 for unlimited). /// Set the depth limits for expressions (0 for unlimited).
@ -115,8 +119,12 @@ impl Engine {
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn max_expr_depth(&self) -> usize { pub const fn max_expr_depth(&self) -> usize {
self.limits.max_expr_depth.map_or(0, NonZeroUsize::get) if let Some(n) = self.limits.max_expr_depth {
n.get()
} else {
0
}
} }
/// The depth limit for expressions in functions (0 for unlimited). /// The depth limit for expressions in functions (0 for unlimited).
/// ///
@ -125,10 +133,12 @@ impl Engine {
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn max_function_expr_depth(&self) -> usize { pub const fn max_function_expr_depth(&self) -> usize {
self.limits if let Some(n) = self.limits.max_function_expr_depth {
.max_function_expr_depth n.get()
.map_or(0, NonZeroUsize::get) } else {
0
}
} }
/// Set the maximum length of [strings][crate::ImmutableString] (0 for unlimited). /// Set the maximum length of [strings][crate::ImmutableString] (0 for unlimited).
/// ///
@ -145,8 +155,12 @@ impl Engine {
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn max_string_size(&self) -> usize { pub const fn max_string_size(&self) -> usize {
self.limits.max_string_size.map_or(0, NonZeroUsize::get) if let Some(n) = self.limits.max_string_size {
n.get()
} else {
0
}
} }
/// Set the maximum length of [arrays][crate::Array] (0 for unlimited). /// Set the maximum length of [arrays][crate::Array] (0 for unlimited).
/// ///
@ -166,7 +180,11 @@ impl Engine {
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn max_array_size(&self) -> usize { pub fn max_array_size(&self) -> usize {
self.limits.max_array_size.map_or(0, NonZeroUsize::get) if let Some(n) = self.limits.max_array_size {
n.get()
} else {
0
}
} }
/// Set the maximum size of [object maps][crate::Map] (0 for unlimited). /// Set the maximum size of [object maps][crate::Map] (0 for unlimited).
/// ///
@ -185,8 +203,12 @@ impl Engine {
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn max_map_size(&self) -> usize { pub const fn max_map_size(&self) -> usize {
self.limits.max_map_size.map_or(0, NonZeroUsize::get) if let Some(n) = self.limits.max_map_size {
n.get()
} else {
0
}
} }
/// Set the module resolution service used by the [`Engine`]. /// Set the module resolution service used by the [`Engine`].
/// ///

View File

@ -237,19 +237,15 @@ impl EvalAltResult {
/// ///
/// [`LoopBreak`][EvalAltResult::LoopBreak] and [`Return`][EvalAltResult::Return] are pseudo errors. /// [`LoopBreak`][EvalAltResult::LoopBreak] and [`Return`][EvalAltResult::Return] are pseudo errors.
#[must_use] #[must_use]
pub fn is_pseudo_error(&self) -> bool { pub const fn is_pseudo_error(&self) -> bool {
match self { match self {
Self::LoopBreak(_, _) | Self::Return(_, _) => true, Self::LoopBreak(_, _) | Self::Return(_, _) => true,
_ => false, _ => false,
} }
} }
/// Can this error be caught? /// Can this error be caught?
///
/// # Panics
///
/// Panics when [`LoopBreak`][EvalAltResult::LoopBreak] or [`Return`][EvalAltResult::Return].
#[must_use] #[must_use]
pub fn is_catchable(&self) -> bool { pub const fn is_catchable(&self) -> bool {
match self { match self {
Self::ErrorSystem(_, _) => false, Self::ErrorSystem(_, _) => false,
Self::ErrorParsing(_, _) => false, Self::ErrorParsing(_, _) => false,
@ -279,17 +275,12 @@ impl EvalAltResult {
| Self::ErrorDataTooLarge(_, _) | Self::ErrorDataTooLarge(_, _)
| Self::ErrorTerminated(_, _) => false, | Self::ErrorTerminated(_, _) => false,
Self::LoopBreak(_, _) => panic!("EvalAltResult::LoopBreak should not occur naturally"), Self::LoopBreak(_, _) | Self::Return(_, _) => false,
Self::Return(_, _) => panic!("EvalAltResult::Return should not occur naturally"),
} }
} }
/// Is this error a system exception? /// Is this error a system exception?
///
/// # Panics
///
/// Panics when [`LoopBreak`][EvalAltResult::LoopBreak] or [`Return`][EvalAltResult::Return].
#[must_use] #[must_use]
pub fn is_system_exception(&self) -> bool { pub const fn is_system_exception(&self) -> bool {
match self { match self {
Self::ErrorSystem(_, _) => true, Self::ErrorSystem(_, _) => true,
Self::ErrorParsing(_, _) => true, Self::ErrorParsing(_, _) => true,
@ -301,9 +292,6 @@ impl EvalAltResult {
Self::ErrorTerminated(_, _) => true, Self::ErrorTerminated(_, _) => true,
Self::LoopBreak(_, _) => panic!("EvalAltResult::LoopBreak should not occur naturally"),
Self::Return(_, _) => panic!("EvalAltResult::Return should not occur naturally"),
_ => false, _ => false,
} }
} }
@ -377,7 +365,7 @@ impl EvalAltResult {
} }
/// Get the [position][Position] of this error. /// Get the [position][Position] of this error.
#[must_use] #[must_use]
pub fn position(&self) -> Position { pub const fn position(&self) -> Position {
match self { match self {
Self::ErrorSystem(_, _) => Position::NONE, Self::ErrorSystem(_, _) => Position::NONE,

View File

@ -14,6 +14,7 @@ use crate::FLOAT;
#[cfg(feature = "decimal")] #[cfg(feature = "decimal")]
use rust_decimal::Decimal; use rust_decimal::Decimal;
/// The message: never fails because this is built-in code and the type is already checked
const BUILTIN: &str = "never fails because this is built-in code and the type is already checked"; const BUILTIN: &str = "never fails because this is built-in code and the type is already checked";
/// Is the type a numeric type? /// Is the type a numeric type?

View File

@ -302,9 +302,13 @@ impl Engine {
let result = if func.is_plugin_fn() { let result = if func.is_plugin_fn() {
func.get_plugin_fn() func.get_plugin_fn()
.expect("never fails because the function is a plugin")
.call((self, name, source, mods, lib).into(), args) .call((self, name, source, mods, lib).into(), args)
} else { } else {
func.get_native_fn()((self, name, source, mods, lib).into(), args) let func = func
.get_native_fn()
.expect("never fails because the function is native");
func((self, name, source, mods, lib).into(), args)
}; };
// Restore the original reference // Restore the original reference
@ -681,7 +685,9 @@ impl Engine {
// Script function call // Script function call
assert!(func.is_script()); assert!(func.is_script());
let func = func.get_fn_def(); let func = func
.get_script_fn_def()
.expect("never fails because the function is scripted");
if func.body.is_empty() { if func.body.is_empty() {
return Ok((Dynamic::UNIT, false)); return Ok((Dynamic::UNIT, false));
@ -1384,7 +1390,9 @@ impl Engine {
match func { match func {
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
Some(f) if f.is_script() => { Some(f) if f.is_script() => {
let fn_def = f.get_fn_def(); let fn_def = f
.get_script_fn_def()
.expect("never fails because the function is scripted");
if fn_def.body.is_empty() { if fn_def.body.is_empty() {
Ok(Dynamic::UNIT) Ok(Dynamic::UNIT)
@ -1408,12 +1416,16 @@ impl Engine {
Some(f) if f.is_plugin_fn() => f Some(f) if f.is_plugin_fn() => f
.get_plugin_fn() .get_plugin_fn()
.expect("never fails because the function is a plugin")
.clone() .clone()
.call((self, fn_name, module.id(), &*mods, lib).into(), &mut args) .call((self, fn_name, module.id(), &*mods, lib).into(), &mut args)
.map_err(|err| err.fill_position(pos)), .map_err(|err| err.fill_position(pos)),
Some(f) if f.is_native() => { Some(f) if f.is_native() => {
f.get_native_fn()((self, fn_name, module.id(), &*mods, lib).into(), &mut args) let func = f
.get_native_fn()
.expect("never fails because the function is native");
func((self, fn_name, module.id(), &*mods, lib).into(), &mut args)
.map_err(|err| err.fill_position(pos)) .map_err(|err| err.fill_position(pos))
} }

View File

@ -108,6 +108,6 @@ pub fn calc_fn_params_hash(params: impl Iterator<Item = TypeId>) -> u64 {
/// Combine two [`u64`] hashes by taking the XOR of them. /// Combine two [`u64`] hashes by taking the XOR of them.
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub(crate) fn combine_hashes(a: u64, b: u64) -> u64 { pub(crate) const fn combine_hashes(a: u64, b: u64) -> u64 {
a ^ b a ^ b
} }

View File

@ -89,7 +89,7 @@ impl<'a> NativeCallContext<'a> {
/// Create a new [`NativeCallContext`]. /// Create a new [`NativeCallContext`].
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn new(engine: &'a Engine, fn_name: &'a str, lib: &'a [&Module]) -> Self { pub const fn new(engine: &'a Engine, fn_name: &'a str, lib: &'a [&Module]) -> Self {
Self { Self {
engine, engine,
fn_name, fn_name,
@ -106,7 +106,7 @@ impl<'a> NativeCallContext<'a> {
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn new_with_all_fields( pub const fn new_with_all_fields(
engine: &'a Engine, engine: &'a Engine,
fn_name: &'a str, fn_name: &'a str,
source: &'a Option<&str>, source: &'a Option<&str>,
@ -124,19 +124,19 @@ impl<'a> NativeCallContext<'a> {
/// The current [`Engine`]. /// The current [`Engine`].
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn engine(&self) -> &Engine { pub const fn engine(&self) -> &Engine {
self.engine self.engine
} }
/// Name of the function called. /// Name of the function called.
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn fn_name(&self) -> &str { pub const fn fn_name(&self) -> &str {
self.fn_name self.fn_name
} }
/// The current source. /// The current source.
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn source(&self) -> Option<&str> { pub const fn source(&self) -> Option<&str> {
self.source self.source
} }
/// Get an iterator over the current set of modules imported via `import` statements. /// Get an iterator over the current set of modules imported via `import` statements.
@ -166,7 +166,7 @@ impl<'a> NativeCallContext<'a> {
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn imports(&self) -> Option<&Imports> { pub const fn imports(&self) -> Option<&Imports> {
self.mods self.mods
} }
/// Get an iterator over the namespaces containing definitions of all script-defined functions. /// Get an iterator over the namespaces containing definitions of all script-defined functions.
@ -180,7 +180,7 @@ impl<'a> NativeCallContext<'a> {
#[cfg(feature = "internals")] #[cfg(feature = "internals")]
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn namespaces(&self) -> &[&Module] { pub const fn namespaces(&self) -> &[&Module] {
self.lib self.lib
} }
/// Call a function inside the call context. /// Call a function inside the call context.
@ -457,74 +457,51 @@ impl CallableFunction {
} }
} }
/// Get a shared reference to a native Rust function. /// Get a shared reference to a native Rust function.
///
/// # Panics
///
/// Panics if the [`CallableFunction`] is not [`Pure`][CallableFunction::Pure] or
/// [`Method`][CallableFunction::Method].
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn get_native_fn(&self) -> &Shared<FnAny> { pub fn get_native_fn(&self) -> Option<&Shared<FnAny>> {
match self { match self {
Self::Pure(f) | Self::Method(f) => f, Self::Pure(f) | Self::Method(f) => Some(f),
Self::Iterator(_) | Self::Plugin(_) => panic!("function should be native"), Self::Iterator(_) | Self::Plugin(_) => None,
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
Self::Script(_) => panic!("function should be native"), Self::Script(_) => None,
} }
} }
/// Get a shared reference to a script-defined function definition. /// Get a shared reference to a script-defined function definition.
/// ///
/// Not available under `no_function`. /// Not available under `no_function`.
///
/// # Panics
///
/// Panics if the [`CallableFunction`] is not [`Script`][CallableFunction::Script].
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn get_fn_def(&self) -> &Shared<crate::ast::ScriptFnDef> { pub const fn get_script_fn_def(&self) -> Option<&Shared<crate::ast::ScriptFnDef>> {
match self { match self {
Self::Pure(_) | Self::Method(_) | Self::Iterator(_) | Self::Plugin(_) => { Self::Pure(_) | Self::Method(_) | Self::Iterator(_) | Self::Plugin(_) => None,
panic!("function should be scripted") Self::Script(f) => Some(f),
}
Self::Script(f) => f,
} }
} }
/// Get a reference to an iterator function. /// Get a reference to an iterator function.
///
/// # Panics
///
/// Panics if the [`CallableFunction`] is not [`Iterator`][CallableFunction::Iterator].
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn get_iter_fn(&self) -> IteratorFn { pub fn get_iter_fn(&self) -> Option<IteratorFn> {
match self { match self {
Self::Iterator(f) => *f, Self::Iterator(f) => Some(*f),
Self::Pure(_) | Self::Method(_) | Self::Plugin(_) => { Self::Pure(_) | Self::Method(_) | Self::Plugin(_) => None,
panic!("function should an iterator")
}
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
Self::Script(_) => panic!("function should be an iterator"), Self::Script(_) => None,
} }
} }
/// Get a shared reference to a plugin function. /// Get a shared reference to a plugin function.
///
/// # Panics
///
/// Panics if the [`CallableFunction`] is not [`Plugin`][CallableFunction::Plugin].
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn get_plugin_fn<'s>(&'s self) -> &Shared<FnPlugin> { pub fn get_plugin_fn<'s>(&'s self) -> Option<&Shared<FnPlugin>> {
match self { match self {
Self::Plugin(f) => f, Self::Plugin(f) => Some(f),
Self::Pure(_) | Self::Method(_) | Self::Iterator(_) => { Self::Pure(_) | Self::Method(_) | Self::Iterator(_) => None,
panic!("function should a plugin")
}
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
Self::Script(_) => panic!("function should a plugin"), Self::Script(_) => None,
} }
} }
/// Create a new [`CallableFunction::Pure`]. /// Create a new [`CallableFunction::Pure`].

View File

@ -38,7 +38,7 @@ impl FnPtr {
/// Get the name of the function. /// Get the name of the function.
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub(crate) fn get_fn_name(&self) -> &Identifier { pub(crate) const fn get_fn_name(&self) -> &Identifier {
&self.0 &self.0
} }
/// Get the underlying data of the function pointer. /// Get the underlying data of the function pointer.

View File

@ -278,7 +278,7 @@ impl Module {
/// Get the ID of the [`Module`] as an [`Identifier`], if any. /// Get the ID of the [`Module`] as an [`Identifier`], if any.
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub(crate) fn id_raw(&self) -> Option<&Identifier> { pub(crate) const fn id_raw(&self) -> Option<&Identifier> {
self.id.as_ref() self.id.as_ref()
} }
@ -358,7 +358,7 @@ impl Module {
/// ``` /// ```
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn is_indexed(&self) -> bool { pub const fn is_indexed(&self) -> bool {
self.indexed self.indexed
} }
@ -508,7 +508,7 @@ impl Module {
self.functions self.functions
.values() .values()
.find(|f| f.params == num_params && f.name == name) .find(|f| f.params == num_params && f.name == name)
.map(|f| f.func.get_fn_def()) .and_then(|f| f.func.get_script_fn_def())
} }
/// Get a mutable reference to the underlying [`BTreeMap`] of sub-modules. /// Get a mutable reference to the underlying [`BTreeMap`] of sub-modules.
@ -1341,7 +1341,9 @@ impl Module {
f.access, f.access,
f.name.as_str(), f.name.as_str(),
f.params, f.params,
f.func.get_fn_def(), f.func
.get_script_fn_def()
.expect("never fails because the function is scripted"),
) )
}) })
} }
@ -1466,7 +1468,12 @@ impl Module {
.filter(|f| f.func.is_script()) .filter(|f| f.func.is_script())
.for_each(|f| { .for_each(|f| {
// Encapsulate AST environment // Encapsulate AST environment
let mut func = f.func.get_fn_def().as_ref().clone(); let mut func = f
.func
.get_script_fn_def()
.expect("never fails because the function is scripted")
.as_ref()
.clone();
func.lib = Some(ast.shared_lib()); func.lib = Some(ast.shared_lib());
func.mods = func_mods.clone(); func.mods = func_mods.clone();
module.set_script_fn(func); module.set_script_fn(func);
@ -1725,7 +1732,7 @@ impl NamespaceRef {
/// Get the [`Scope`][crate::Scope] index offset. /// Get the [`Scope`][crate::Scope] index offset.
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub(crate) fn index(&self) -> Option<NonZeroUsize> { pub(crate) const fn index(&self) -> Option<NonZeroUsize> {
self.index self.index
} }
/// Set the [`Scope`][crate::Scope] index offset. /// Set the [`Scope`][crate::Scope] index offset.

View File

@ -61,7 +61,7 @@ struct State<'a> {
impl<'a> State<'a> { impl<'a> State<'a> {
/// Create a new State. /// Create a new State.
#[inline(always)] #[inline(always)]
pub fn new( pub const fn new(
engine: &'a Engine, engine: &'a Engine,
lib: &'a [&'a Module], lib: &'a [&'a Module],
optimization_level: OptimizationLevel, optimization_level: OptimizationLevel,
@ -87,7 +87,7 @@ impl<'a> State<'a> {
} }
/// Is the [`AST`] dirty (i.e. changed)? /// Is the [`AST`] dirty (i.e. changed)?
#[inline(always)] #[inline(always)]
pub fn is_dirty(&self) -> bool { pub const fn is_dirty(&self) -> bool {
self.changed self.changed
} }
/// Prune the list of constants back to a specified size. /// Prune the list of constants back to a specified size.

View File

@ -5,7 +5,8 @@ use crate::ast::{
ScriptFnDef, Stmt, StmtBlock, ScriptFnDef, Stmt, StmtBlock,
}; };
use crate::custom_syntax::{ use crate::custom_syntax::{
CustomSyntax, MARKER_BLOCK, MARKER_BOOL, MARKER_EXPR, MARKER_IDENT, MARKER_INT, MARKER_STRING, CustomSyntax, CUSTOM_SYNTAX_MARKER_BLOCK, CUSTOM_SYNTAX_MARKER_BOOL, CUSTOM_SYNTAX_MARKER_EXPR,
CUSTOM_SYNTAX_MARKER_IDENT, CUSTOM_SYNTAX_MARKER_INT, CUSTOM_SYNTAX_MARKER_STRING,
}; };
use crate::dynamic::{AccessMode, Union}; use crate::dynamic::{AccessMode, Union};
use crate::engine::{Precedence, KEYWORD_THIS, OP_CONTAINS}; use crate::engine::{Precedence, KEYWORD_THIS, OP_CONTAINS};
@ -29,7 +30,7 @@ use std::{
}; };
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
use crate::{custom_syntax::MARKER_FLOAT, FLOAT}; use crate::{custom_syntax::CUSTOM_SYNTAX_MARKER_FLOAT, FLOAT};
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
use crate::FnAccess; use crate::FnAccess;
@ -38,6 +39,10 @@ type PERR = ParseErrorType;
type FunctionsLib = BTreeMap<u64, Shared<ScriptFnDef>>; type FunctionsLib = BTreeMap<u64, Shared<ScriptFnDef>>;
/// Invalid variable name that acts as a search barrier in a [`Scope`].
const SCOPE_SEARCH_BARRIER_MARKER: &str = "$BARRIER$";
/// The message: never fails because `TokenStream` never ends
const NEVER_ENDS: &str = "never fails because `TokenStream` never ends"; const NEVER_ENDS: &str = "never fails because `TokenStream` never ends";
/// A factory of identifiers from text strings. /// A factory of identifiers from text strings.
@ -147,8 +152,8 @@ impl<'e> ParseState<'e> {
.rev() .rev()
.enumerate() .enumerate()
.find(|(_, (n, _))| { .find(|(_, (n, _))| {
if n.is_empty() { if n == SCOPE_SEARCH_BARRIER_MARKER {
// Do not go beyond empty variable names // Do not go beyond the barrier
barrier = true; barrier = true;
false false
} else { } else {
@ -230,7 +235,7 @@ impl ParseSettings {
/// Create a new `ParseSettings` with one higher expression level. /// Create a new `ParseSettings` with one higher expression level.
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn level_up(&self) -> Self { pub const fn level_up(&self) -> Self {
Self { Self {
level: self.level + 1, level: self.level + 1,
..*self ..*self
@ -244,8 +249,10 @@ impl ParseSettings {
&self, &self,
limit: Option<NonZeroUsize>, limit: Option<NonZeroUsize>,
) -> Result<(), ParseError> { ) -> Result<(), ParseError> {
if limit.map(|limit| self.level > limit.get()).unwrap_or(false) { if let Some(limit) = limit {
return Err(PERR::ExprTooDeep.into_err(self.pos)); if self.level > limit.get() {
return Err(PERR::ExprTooDeep.into_err(self.pos));
}
} }
Ok(()) Ok(())
} }
@ -1894,7 +1901,7 @@ fn parse_custom_syntax(
// Add an empty variable name to the stack. // Add an empty variable name to the stack.
// Empty variable names act as a barrier so earlier variables will not be matched. // Empty variable names act as a barrier so earlier variables will not be matched.
// Variable searches stop at the first empty variable name. // Variable searches stop at the first empty variable name.
let empty = state.get_identifier(""); let empty = state.get_identifier(SCOPE_SEARCH_BARRIER_MARKER);
state.stack.push((empty, AccessMode::ReadWrite)); state.stack.push((empty, AccessMode::ReadWrite));
} }
@ -1915,32 +1922,32 @@ fn parse_custom_syntax(
}; };
match required_token.as_str() { match required_token.as_str() {
MARKER_IDENT => { CUSTOM_SYNTAX_MARKER_IDENT => {
let (name, pos) = parse_var_name(input)?; let (name, pos) = parse_var_name(input)?;
let name = state.get_identifier(name); let name = state.get_identifier(name);
segments.push(name.clone().into()); segments.push(name.clone().into());
tokens.push(state.get_identifier(MARKER_IDENT)); tokens.push(state.get_identifier(CUSTOM_SYNTAX_MARKER_IDENT));
keywords.push(Expr::Variable(None, pos, Box::new((None, None, name)))); keywords.push(Expr::Variable(None, pos, Box::new((None, None, name))));
} }
MARKER_EXPR => { CUSTOM_SYNTAX_MARKER_EXPR => {
keywords.push(parse_expr(input, state, lib, settings)?); keywords.push(parse_expr(input, state, lib, settings)?);
let keyword = state.get_identifier(MARKER_EXPR); let keyword = state.get_identifier(CUSTOM_SYNTAX_MARKER_EXPR);
segments.push(keyword.clone().into()); segments.push(keyword.clone().into());
tokens.push(keyword); tokens.push(keyword);
} }
MARKER_BLOCK => match parse_block(input, state, lib, settings)? { CUSTOM_SYNTAX_MARKER_BLOCK => match parse_block(input, state, lib, settings)? {
block @ Stmt::Block(_, _) => { block @ Stmt::Block(_, _) => {
keywords.push(Expr::Stmt(Box::new(block.into()))); keywords.push(Expr::Stmt(Box::new(block.into())));
let keyword = state.get_identifier(MARKER_BLOCK); let keyword = state.get_identifier(CUSTOM_SYNTAX_MARKER_BLOCK);
segments.push(keyword.clone().into()); segments.push(keyword.clone().into());
tokens.push(keyword); tokens.push(keyword);
} }
stmt => unreachable!("expecting Stmt::Block, but gets {:?}", stmt), stmt => unreachable!("expecting Stmt::Block, but gets {:?}", stmt),
}, },
MARKER_BOOL => match input.next().expect(NEVER_ENDS) { CUSTOM_SYNTAX_MARKER_BOOL => match input.next().expect(NEVER_ENDS) {
(b @ Token::True, pos) | (b @ Token::False, pos) => { (b @ Token::True, pos) | (b @ Token::False, pos) => {
keywords.push(Expr::BoolConstant(b == Token::True, pos)); keywords.push(Expr::BoolConstant(b == Token::True, pos));
let keyword = state.get_identifier(MARKER_BOOL); let keyword = state.get_identifier(CUSTOM_SYNTAX_MARKER_BOOL);
segments.push(keyword.clone().into()); segments.push(keyword.clone().into());
tokens.push(keyword); tokens.push(keyword);
} }
@ -1951,10 +1958,10 @@ fn parse_custom_syntax(
) )
} }
}, },
MARKER_INT => match input.next().expect(NEVER_ENDS) { CUSTOM_SYNTAX_MARKER_INT => match input.next().expect(NEVER_ENDS) {
(Token::IntegerConstant(i), pos) => { (Token::IntegerConstant(i), pos) => {
keywords.push(Expr::IntegerConstant(i, pos)); keywords.push(Expr::IntegerConstant(i, pos));
let keyword = state.get_identifier(MARKER_INT); let keyword = state.get_identifier(CUSTOM_SYNTAX_MARKER_INT);
segments.push(keyword.clone().into()); segments.push(keyword.clone().into());
tokens.push(keyword); tokens.push(keyword);
} }
@ -1966,10 +1973,10 @@ fn parse_custom_syntax(
} }
}, },
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
MARKER_FLOAT => match input.next().expect(NEVER_ENDS) { CUSTOM_SYNTAX_MARKER_FLOAT => match input.next().expect(NEVER_ENDS) {
(Token::FloatConstant(f), pos) => { (Token::FloatConstant(f), pos) => {
keywords.push(Expr::FloatConstant(f, pos)); keywords.push(Expr::FloatConstant(f, pos));
let keyword = state.get_identifier(MARKER_FLOAT); let keyword = state.get_identifier(CUSTOM_SYNTAX_MARKER_FLOAT);
segments.push(keyword.clone().into()); segments.push(keyword.clone().into());
tokens.push(keyword); tokens.push(keyword);
} }
@ -1980,10 +1987,10 @@ fn parse_custom_syntax(
.into_err(pos)) .into_err(pos))
} }
}, },
MARKER_STRING => match input.next().expect(NEVER_ENDS) { CUSTOM_SYNTAX_MARKER_STRING => match input.next().expect(NEVER_ENDS) {
(Token::StringConstant(s), pos) => { (Token::StringConstant(s), pos) => {
keywords.push(Expr::StringConstant(state.get_identifier(s).into(), pos)); keywords.push(Expr::StringConstant(state.get_identifier(s).into(), pos));
let keyword = state.get_identifier(MARKER_STRING); let keyword = state.get_identifier(CUSTOM_SYNTAX_MARKER_STRING);
segments.push(keyword.clone().into()); segments.push(keyword.clone().into());
tokens.push(keyword); tokens.push(keyword);
} }

View File

@ -7,7 +7,7 @@ use std::prelude::v1::*;
use std::{borrow::Cow, iter::Extend}; use std::{borrow::Cow, iter::Extend};
/// Keep a number of entries inline (since [`Dynamic`] is usually small enough). /// Keep a number of entries inline (since [`Dynamic`] is usually small enough).
const SCOPE_SIZE: usize = 8; const SCOPE_ENTRIES_INLINED: usize = 8;
/// Type containing information about the current scope. /// Type containing information about the current scope.
/// Useful for keeping state between [`Engine`][crate::Engine] evaluation runs. /// Useful for keeping state between [`Engine`][crate::Engine] evaluation runs.
@ -54,7 +54,7 @@ const SCOPE_SIZE: usize = 8;
#[derive(Debug, Clone, Hash)] #[derive(Debug, Clone, Hash)]
pub struct Scope<'a> { pub struct Scope<'a> {
/// Current value of the entry. /// Current value of the entry.
values: smallvec::SmallVec<[Dynamic; SCOPE_SIZE]>, values: smallvec::SmallVec<[Dynamic; SCOPE_ENTRIES_INLINED]>,
/// (Name, aliases) of the entry. /// (Name, aliases) of the entry.
names: Vec<(Cow<'a, str>, Option<Box<StaticVec<Identifier>>>)>, names: Vec<(Cow<'a, str>, Option<Box<StaticVec<Identifier>>>)>,
} }
@ -161,7 +161,7 @@ impl<'a> Scope<'a> {
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
self.values.len() == 0 self.values.is_empty()
} }
/// Add (push) a new entry to the [`Scope`]. /// Add (push) a new entry to the [`Scope`].
/// ///

View File

@ -41,7 +41,7 @@ pub type TokenizerControl = Rc<Cell<TokenizerControlBlock>>;
type LERR = LexError; type LERR = LexError;
/// Separator character for numbers. /// Separator character for numbers.
const NUM_SEP: char = '_'; const NUMBER_SEPARATOR: char = '_';
/// A stream of tokens. /// A stream of tokens.
pub type TokenStream<'a> = Peekable<TokenIterator<'a>>; pub type TokenStream<'a> = Peekable<TokenIterator<'a>>;
@ -110,7 +110,7 @@ impl Position {
#[cfg(not(feature = "no_position"))] #[cfg(not(feature = "no_position"))]
return Some(self.line as usize); return Some(self.line as usize);
#[cfg(feature = "no_position")] #[cfg(feature = "no_position")]
unreachable!(); unreachable!("there is no Position");
} }
} }
/// Get the character position (1-based), or [`None`] if at beginning of a line. /// Get the character position (1-based), or [`None`] if at beginning of a line.
@ -128,7 +128,7 @@ impl Position {
}; };
#[cfg(feature = "no_position")] #[cfg(feature = "no_position")]
unreachable!(); unreachable!("there is no Position");
} }
} }
/// Advance by one character position. /// Advance by one character position.
@ -175,7 +175,7 @@ impl Position {
/// Is this [`Position`] at the beginning of a line? /// Is this [`Position`] at the beginning of a line?
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn is_beginning_of_line(self) -> bool { pub const fn is_beginning_of_line(self) -> bool {
#[cfg(not(feature = "no_position"))] #[cfg(not(feature = "no_position"))]
return self.pos == 0 && !self.is_none(); return self.pos == 0 && !self.is_none();
#[cfg(feature = "no_position")] #[cfg(feature = "no_position")]
@ -184,9 +184,9 @@ impl Position {
/// Is there no [`Position`]? /// Is there no [`Position`]?
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn is_none(self) -> bool { pub const fn is_none(self) -> bool {
#[cfg(not(feature = "no_position"))] #[cfg(not(feature = "no_position"))]
return self == Self::NONE; return self.line == 0 && self.pos == 0;
#[cfg(feature = "no_position")] #[cfg(feature = "no_position")]
return true; return true;
} }
@ -467,12 +467,8 @@ pub enum Token {
impl Token { impl Token {
/// Get the syntax of the token if it is a keyword. /// Get the syntax of the token if it is a keyword.
///
/// # Panics
///
/// Panics if the token is not a keyword.
#[must_use] #[must_use]
pub fn keyword_syntax(&self) -> &'static str { pub const fn keyword_syntax(&self) -> &'static str {
use Token::*; use Token::*;
match self { match self {
@ -556,7 +552,7 @@ impl Token {
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
As => "as", As => "as",
t => unreachable!("{:?} is not a keyword", t), _ => "ERROR: NOT A KEYWORD",
} }
} }
@ -589,7 +585,7 @@ impl Token {
/// Is this token an op-assignment operator? /// Is this token an op-assignment operator?
#[inline] #[inline]
#[must_use] #[must_use]
pub fn is_op_assignment(&self) -> bool { pub const fn is_op_assignment(&self) -> bool {
match self { match self {
Self::PlusAssign Self::PlusAssign
| Self::MinusAssign | Self::MinusAssign
@ -608,7 +604,7 @@ impl Token {
/// Get the corresponding operator of the token if it is an op-assignment operator. /// Get the corresponding operator of the token if it is an op-assignment operator.
#[must_use] #[must_use]
pub fn map_op_assignment(&self) -> Option<Self> { pub const fn map_op_assignment(&self) -> Option<Self> {
Some(match self { Some(match self {
Self::PlusAssign => Self::Plus, Self::PlusAssign => Self::Plus,
Self::MinusAssign => Self::Minus, Self::MinusAssign => Self::Minus,
@ -628,7 +624,7 @@ impl Token {
/// Has this token a corresponding op-assignment operator? /// Has this token a corresponding op-assignment operator?
#[inline] #[inline]
#[must_use] #[must_use]
pub fn has_op_assignment(&self) -> bool { pub const fn has_op_assignment(&self) -> bool {
match self { match self {
Self::Plus Self::Plus
| Self::Minus | Self::Minus
@ -647,7 +643,7 @@ impl Token {
/// Get the corresponding op-assignment operator of the token. /// Get the corresponding op-assignment operator of the token.
#[must_use] #[must_use]
pub fn make_op_assignment(&self) -> Option<Self> { pub const fn make_op_assignment(&self) -> Option<Self> {
Some(match self { Some(match self {
Self::Plus => Self::PlusAssign, Self::Plus => Self::PlusAssign,
Self::Minus => Self::MinusAssign, Self::Minus => Self::MinusAssign,
@ -777,7 +773,7 @@ impl Token {
// Is this token [`EOF`][Token::EOF]? // Is this token [`EOF`][Token::EOF]?
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn is_eof(&self) -> bool { pub const fn is_eof(&self) -> bool {
use Token::*; use Token::*;
match self { match self {
@ -789,7 +785,7 @@ impl Token {
// If another operator is after these, it's probably an unary operator // If another operator is after these, it's probably an unary operator
// (not sure about `fn` name). // (not sure about `fn` name).
#[must_use] #[must_use]
pub fn is_next_unary(&self) -> bool { pub const fn is_next_unary(&self) -> bool {
use Token::*; use Token::*;
match self { match self {
@ -850,7 +846,7 @@ impl Token {
/// Get the precedence number of the token. /// Get the precedence number of the token.
#[must_use] #[must_use]
pub fn precedence(&self) -> Option<Precedence> { pub const fn precedence(&self) -> Option<Precedence> {
use Token::*; use Token::*;
Precedence::new(match self { Precedence::new(match self {
@ -885,7 +881,7 @@ impl Token {
/// Does an expression bind to the right (instead of left)? /// Does an expression bind to the right (instead of left)?
#[must_use] #[must_use]
pub fn is_bind_right(&self) -> bool { pub const fn is_bind_right(&self) -> bool {
use Token::*; use Token::*;
match self { match self {
@ -906,7 +902,7 @@ impl Token {
/// Is this token a standard symbol used in the language? /// Is this token a standard symbol used in the language?
#[must_use] #[must_use]
pub fn is_symbol(&self) -> bool { pub const fn is_symbol(&self) -> bool {
use Token::*; use Token::*;
match self { match self {
@ -924,7 +920,7 @@ impl Token {
/// Is this token an active standard keyword? /// Is this token an active standard keyword?
#[must_use] #[must_use]
pub fn is_keyword(&self) -> bool { pub const fn is_keyword(&self) -> bool {
use Token::*; use Token::*;
match self { match self {
@ -944,7 +940,7 @@ impl Token {
/// Is this token a reserved symbol? /// Is this token a reserved symbol?
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn is_reserved(&self) -> bool { pub const fn is_reserved(&self) -> bool {
match self { match self {
Self::Reserved(_) => true, Self::Reserved(_) => true,
_ => false, _ => false,
@ -964,7 +960,7 @@ impl Token {
/// Is this token a custom keyword? /// Is this token a custom keyword?
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn is_custom(&self) -> bool { pub const fn is_custom(&self) -> bool {
match self { match self {
Self::Custom(_) => true, Self::Custom(_) => true,
_ => false, _ => false,
@ -1435,7 +1431,7 @@ fn get_next_token_inner(
while let Some(next_char) = stream.peek_next() { while let Some(next_char) = stream.peek_next() {
match next_char { match next_char {
ch if valid(ch) || ch == NUM_SEP => { ch if valid(ch) || ch == NUMBER_SEPARATOR => {
result.push(next_char); result.push(next_char);
eat_next(stream, pos); eat_next(stream, pos);
} }
@ -1536,8 +1532,11 @@ fn get_next_token_inner(
// Parse number // Parse number
return Some(( return Some((
if let Some(radix) = radix_base { if let Some(radix) = radix_base {
let out: String = let out: String = result
result.iter().skip(2).filter(|&&c| c != NUM_SEP).collect(); .iter()
.skip(2)
.filter(|&&c| c != NUMBER_SEPARATOR)
.collect();
INT::from_str_radix(&out, radix) INT::from_str_radix(&out, radix)
.map(Token::IntegerConstant) .map(Token::IntegerConstant)
@ -1545,7 +1544,8 @@ fn get_next_token_inner(
Token::LexError(LERR::MalformedNumber(result.into_iter().collect())) Token::LexError(LERR::MalformedNumber(result.into_iter().collect()))
}) })
} else { } else {
let out: String = result.iter().filter(|&&c| c != NUM_SEP).collect(); let out: String =
result.iter().filter(|&&c| c != NUMBER_SEPARATOR).collect();
let num = INT::from_str(&out).map(Token::IntegerConstant); let num = INT::from_str(&out).map(Token::IntegerConstant);
// If integer parsing is unnecessary, try float instead // If integer parsing is unnecessary, try float instead