Mark simple functions const.
This commit is contained in:
parent
0c99165007
commit
e40e81ac1a
34
src/ast.rs
34
src/ast.rs
@ -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.
|
||||||
|
@ -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
|
||||||
|
@ -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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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")]
|
||||||
|
@ -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`].
|
||||||
///
|
///
|
||||||
|
22
src/error.rs
22
src/error.rs
@ -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,
|
||||||
|
|
||||||
|
@ -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?
|
||||||
|
@ -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))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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`].
|
||||||
|
@ -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.
|
||||||
|
@ -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.
|
||||||
|
@ -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.
|
||||||
|
51
src/parse.rs
51
src/parse.rs
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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`].
|
||||||
///
|
///
|
||||||
|
56
src/token.rs
56
src/token.rs
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user