commit
e55f962b2d
@ -3,7 +3,7 @@ members = [".", "codegen"]
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "rhai"
|
name = "rhai"
|
||||||
version = "1.0.0"
|
version = "1.0.3"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
authors = ["Jonathan Turner", "Lukáš Hozda", "Stephen Chung", "jhwgh1968"]
|
authors = ["Jonathan Turner", "Lukáš Hozda", "Stephen Chung", "jhwgh1968"]
|
||||||
description = "Embedded scripting for Rust"
|
description = "Embedded scripting for Rust"
|
||||||
|
@ -10,7 +10,7 @@ error[E0412]: cannot find type `Pointer` in this scope
|
|||||||
help: a struct with a similar name exists
|
help: a struct with a similar name exists
|
||||||
|
|
|
|
||||||
12 | pub fn test_fn(input: Point) -> bool {
|
12 | pub fn test_fn(input: Point) -> bool {
|
||||||
| ^^^^^
|
| ~~~~~
|
||||||
help: consider importing one of these items
|
help: consider importing one of these items
|
||||||
|
|
|
|
||||||
11 | use core::fmt::Pointer;
|
11 | use core::fmt::Pointer;
|
||||||
|
@ -81,7 +81,7 @@ impl Expression<'_> {
|
|||||||
/// [`ImmutableString`][crate::ImmutableString].
|
/// [`ImmutableString`][crate::ImmutableString].
|
||||||
///
|
///
|
||||||
/// Returns [`None`] also if the constant is not of the specified type.
|
/// Returns [`None`] also if the constant is not of the specified type.
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_literal_value<T: Variant>(&self) -> Option<T> {
|
pub fn get_literal_value<T: Variant>(&self) -> Option<T> {
|
||||||
// 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.
|
||||||
|
@ -1038,7 +1038,7 @@ impl Dynamic {
|
|||||||
/// assert_eq!(new_result.type_name(), "string");
|
/// assert_eq!(new_result.type_name(), "string");
|
||||||
/// assert_eq!(new_result.to_string(), "hello");
|
/// assert_eq!(new_result.to_string(), "hello");
|
||||||
/// ```
|
/// ```
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
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.
|
||||||
@ -1179,7 +1179,7 @@ impl Dynamic {
|
|||||||
///
|
///
|
||||||
/// assert_eq!(x.try_cast::<u32>().unwrap(), 42);
|
/// assert_eq!(x.try_cast::<u32>().unwrap(), 42);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn try_cast<T: Any>(self) -> Option<T> {
|
pub fn try_cast<T: Any>(self) -> Option<T> {
|
||||||
// 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.
|
||||||
@ -1538,7 +1538,7 @@ impl Dynamic {
|
|||||||
/// Casting to [`Dynamic`] just returns a reference to it.
|
/// Casting to [`Dynamic`] just returns a reference to it.
|
||||||
///
|
///
|
||||||
/// Returns [`None`] if the cast fails, or if the value is shared.
|
/// Returns [`None`] if the cast fails, or if the value is shared.
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) fn downcast_ref<T: Any + Clone + ?Sized>(&self) -> Option<&T> {
|
pub(crate) fn downcast_ref<T: Any + Clone + ?Sized>(&self) -> Option<&T> {
|
||||||
// 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.
|
||||||
@ -1629,7 +1629,7 @@ impl Dynamic {
|
|||||||
/// Casting to [`Dynamic`] just returns a mutable reference to it.
|
/// Casting to [`Dynamic`] just returns a mutable reference to it.
|
||||||
///
|
///
|
||||||
/// Returns [`None`] if the cast fails, or if the value is shared.
|
/// Returns [`None`] if the cast fails, or if the value is shared.
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) fn downcast_mut<T: Any + Clone>(&mut self) -> Option<&mut T> {
|
pub(crate) fn downcast_mut<T: Any + Clone>(&mut self) -> Option<&mut T> {
|
||||||
// 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.
|
||||||
@ -1728,7 +1728,7 @@ impl Dynamic {
|
|||||||
}
|
}
|
||||||
/// Cast the [`Dynamic`] as a unit `()` and return it.
|
/// Cast the [`Dynamic`] as a unit `()` and return it.
|
||||||
/// Returns the name of the actual type if the cast fails.
|
/// Returns the name of the actual type if the cast fails.
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
pub fn as_unit(&self) -> Result<(), &'static str> {
|
pub fn as_unit(&self) -> Result<(), &'static str> {
|
||||||
match self.0 {
|
match self.0 {
|
||||||
Union::Unit(value, _, _) => Ok(value),
|
Union::Unit(value, _, _) => Ok(value),
|
||||||
@ -1739,7 +1739,7 @@ impl Dynamic {
|
|||||||
}
|
}
|
||||||
/// Cast the [`Dynamic`] as the system integer type [`INT`] and return it.
|
/// Cast the [`Dynamic`] as the system integer type [`INT`] and return it.
|
||||||
/// Returns the name of the actual type if the cast fails.
|
/// Returns the name of the actual type if the cast fails.
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
pub fn as_int(&self) -> Result<INT, &'static str> {
|
pub fn as_int(&self) -> Result<INT, &'static str> {
|
||||||
match self.0 {
|
match self.0 {
|
||||||
Union::Int(n, _, _) => Ok(n),
|
Union::Int(n, _, _) => Ok(n),
|
||||||
@ -1753,7 +1753,7 @@ impl Dynamic {
|
|||||||
///
|
///
|
||||||
/// Not available under `no_float`.
|
/// Not available under `no_float`.
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
pub fn as_float(&self) -> Result<FLOAT, &'static str> {
|
pub fn as_float(&self) -> Result<FLOAT, &'static str> {
|
||||||
match self.0 {
|
match self.0 {
|
||||||
Union::Float(n, _, _) => Ok(*n),
|
Union::Float(n, _, _) => Ok(*n),
|
||||||
@ -1767,7 +1767,7 @@ impl Dynamic {
|
|||||||
///
|
///
|
||||||
/// Exported under the `decimal` feature only.
|
/// Exported under the `decimal` feature only.
|
||||||
#[cfg(feature = "decimal")]
|
#[cfg(feature = "decimal")]
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
pub fn as_decimal(&self) -> Result<Decimal, &'static str> {
|
pub fn as_decimal(&self) -> Result<Decimal, &'static str> {
|
||||||
match self.0 {
|
match self.0 {
|
||||||
Union::Decimal(ref n, _, _) => Ok(**n),
|
Union::Decimal(ref n, _, _) => Ok(**n),
|
||||||
@ -1778,7 +1778,7 @@ impl Dynamic {
|
|||||||
}
|
}
|
||||||
/// Cast the [`Dynamic`] as a [`bool`] and return it.
|
/// Cast the [`Dynamic`] as a [`bool`] and return it.
|
||||||
/// Returns the name of the actual type if the cast fails.
|
/// Returns the name of the actual type if the cast fails.
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
pub fn as_bool(&self) -> Result<bool, &'static str> {
|
pub fn as_bool(&self) -> Result<bool, &'static str> {
|
||||||
match self.0 {
|
match self.0 {
|
||||||
Union::Bool(b, _, _) => Ok(b),
|
Union::Bool(b, _, _) => Ok(b),
|
||||||
@ -1789,7 +1789,7 @@ impl Dynamic {
|
|||||||
}
|
}
|
||||||
/// Cast the [`Dynamic`] as a [`char`] and return it.
|
/// Cast the [`Dynamic`] as a [`char`] and return it.
|
||||||
/// Returns the name of the actual type if the cast fails.
|
/// Returns the name of the actual type if the cast fails.
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
pub fn as_char(&self) -> Result<char, &'static str> {
|
pub fn as_char(&self) -> Result<char, &'static str> {
|
||||||
match self.0 {
|
match self.0 {
|
||||||
Union::Char(n, _, _) => Ok(n),
|
Union::Char(n, _, _) => Ok(n),
|
||||||
@ -1804,7 +1804,7 @@ impl Dynamic {
|
|||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// Panics if the value is shared.
|
/// Panics if the value is shared.
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
pub(crate) fn as_str_ref(&self) -> Result<&str, &'static str> {
|
pub(crate) fn as_str_ref(&self) -> Result<&str, &'static str> {
|
||||||
match self.0 {
|
match self.0 {
|
||||||
Union::Str(ref s, _, _) => Ok(s),
|
Union::Str(ref s, _, _) => Ok(s),
|
||||||
@ -1816,7 +1816,7 @@ impl Dynamic {
|
|||||||
/// Convert the [`Dynamic`] into a [`String`] and return it.
|
/// Convert the [`Dynamic`] into a [`String`] and return it.
|
||||||
/// If there are other references to the same string, a cloned copy is returned.
|
/// If there are other references to the same string, a cloned copy is returned.
|
||||||
/// Returns the name of the actual type if the cast fails.
|
/// Returns the name of the actual type if the cast fails.
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
pub fn as_string(self) -> Result<String, &'static str> {
|
pub fn as_string(self) -> Result<String, &'static str> {
|
||||||
self.as_immutable_string().map(ImmutableString::into_owned)
|
self.as_immutable_string().map(ImmutableString::into_owned)
|
||||||
}
|
}
|
||||||
@ -1954,7 +1954,7 @@ impl Dynamic {
|
|||||||
impl<K: Into<crate::Identifier>, T: Variant + Clone> From<std::collections::HashMap<K, T>>
|
impl<K: Into<crate::Identifier>, T: Variant + Clone> From<std::collections::HashMap<K, T>>
|
||||||
for Dynamic
|
for Dynamic
|
||||||
{
|
{
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
fn from(value: std::collections::HashMap<K, T>) -> Self {
|
fn from(value: std::collections::HashMap<K, T>) -> Self {
|
||||||
Self(Union::Map(
|
Self(Union::Map(
|
||||||
Box::new(
|
Box::new(
|
||||||
@ -1971,7 +1971,7 @@ impl<K: Into<crate::Identifier>, T: Variant + Clone> From<std::collections::Hash
|
|||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
#[cfg(not(feature = "no_std"))]
|
#[cfg(not(feature = "no_std"))]
|
||||||
impl<K: Into<crate::Identifier>> From<std::collections::HashSet<K>> for Dynamic {
|
impl<K: Into<crate::Identifier>> From<std::collections::HashSet<K>> for Dynamic {
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
fn from(value: std::collections::HashSet<K>) -> Self {
|
fn from(value: std::collections::HashSet<K>) -> Self {
|
||||||
Self(Union::Map(
|
Self(Union::Map(
|
||||||
Box::new(
|
Box::new(
|
||||||
@ -1989,7 +1989,7 @@ impl<K: Into<crate::Identifier>> From<std::collections::HashSet<K>> for Dynamic
|
|||||||
impl<K: Into<crate::Identifier>, T: Variant + Clone> From<std::collections::BTreeMap<K, T>>
|
impl<K: Into<crate::Identifier>, T: Variant + Clone> From<std::collections::BTreeMap<K, T>>
|
||||||
for Dynamic
|
for Dynamic
|
||||||
{
|
{
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
fn from(value: std::collections::BTreeMap<K, T>) -> Self {
|
fn from(value: std::collections::BTreeMap<K, T>) -> Self {
|
||||||
Self(Union::Map(
|
Self(Union::Map(
|
||||||
Box::new(
|
Box::new(
|
||||||
@ -2005,7 +2005,7 @@ impl<K: Into<crate::Identifier>, T: Variant + Clone> From<std::collections::BTre
|
|||||||
}
|
}
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
impl<K: Into<crate::Identifier>> From<std::collections::BTreeSet<K>> for Dynamic {
|
impl<K: Into<crate::Identifier>> From<std::collections::BTreeSet<K>> for Dynamic {
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
fn from(value: std::collections::BTreeSet<K>) -> Self {
|
fn from(value: std::collections::BTreeSet<K>) -> Self {
|
||||||
Self(Union::Map(
|
Self(Union::Map(
|
||||||
Box::new(
|
Box::new(
|
||||||
|
@ -98,7 +98,7 @@ impl Imports {
|
|||||||
self.modules.get_mut(index)
|
self.modules.get_mut(index)
|
||||||
}
|
}
|
||||||
/// Get the index of an imported [module][Module] by name.
|
/// Get the index of an imported [module][Module] by name.
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn find(&self, name: &str) -> Option<usize> {
|
pub fn find(&self, name: &str) -> Option<usize> {
|
||||||
self.keys
|
self.keys
|
||||||
@ -121,7 +121,7 @@ impl Imports {
|
|||||||
}
|
}
|
||||||
/// Get an iterator to this stack of imported [modules][Module] in reverse order.
|
/// Get an iterator to this stack of imported [modules][Module] in reverse order.
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
pub fn iter(&self) -> impl Iterator<Item = (&str, &Module)> {
|
pub fn iter(&self) -> impl Iterator<Item = (&str, &Module)> {
|
||||||
self.keys
|
self.keys
|
||||||
.iter()
|
.iter()
|
||||||
@ -131,13 +131,13 @@ impl Imports {
|
|||||||
}
|
}
|
||||||
/// Get an iterator to this stack of imported [modules][Module] in reverse order.
|
/// Get an iterator to this stack of imported [modules][Module] in reverse order.
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
pub(crate) fn iter_raw(&self) -> impl Iterator<Item = (&Identifier, &Shared<Module>)> {
|
pub(crate) fn iter_raw(&self) -> impl Iterator<Item = (&Identifier, &Shared<Module>)> {
|
||||||
self.keys.iter().rev().zip(self.modules.iter().rev())
|
self.keys.iter().rev().zip(self.modules.iter().rev())
|
||||||
}
|
}
|
||||||
/// Get an iterator to this stack of imported [modules][Module] in forward order.
|
/// Get an iterator to this stack of imported [modules][Module] in forward order.
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
pub(crate) fn scan_raw(&self) -> impl Iterator<Item = (&Identifier, &Shared<Module>)> {
|
pub(crate) fn scan_raw(&self) -> impl Iterator<Item = (&Identifier, &Shared<Module>)> {
|
||||||
self.keys.iter().zip(self.modules.iter())
|
self.keys.iter().zip(self.modules.iter())
|
||||||
}
|
}
|
||||||
@ -149,7 +149,7 @@ impl Imports {
|
|||||||
self.modules.iter().any(|m| m.contains_qualified_fn(hash))
|
self.modules.iter().any(|m| m.contains_qualified_fn(hash))
|
||||||
}
|
}
|
||||||
/// Get the specified function via its hash key from this stack of imported [modules][Module].
|
/// Get the specified function via its hash key from this stack of imported [modules][Module].
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_fn(&self, hash: u64) -> Option<(&CallableFunction, Option<&Identifier>)> {
|
pub fn get_fn(&self, hash: u64) -> Option<(&CallableFunction, Option<&Identifier>)> {
|
||||||
self.modules
|
self.modules
|
||||||
@ -167,7 +167,7 @@ impl Imports {
|
|||||||
}
|
}
|
||||||
/// Get the specified [`TypeId`][std::any::TypeId] iterator from this stack of imported
|
/// Get the specified [`TypeId`][std::any::TypeId] iterator from this stack of imported
|
||||||
/// [modules][Module].
|
/// [modules][Module].
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_iter(&self, id: TypeId) -> Option<IteratorFn> {
|
pub fn get_iter(&self, id: TypeId) -> Option<IteratorFn> {
|
||||||
self.modules
|
self.modules
|
||||||
@ -182,7 +182,7 @@ impl IntoIterator for Imports {
|
|||||||
type IntoIter =
|
type IntoIter =
|
||||||
Zip<Rev<smallvec::IntoIter<[Identifier; 4]>>, Rev<smallvec::IntoIter<[Shared<Module>; 4]>>>;
|
Zip<Rev<smallvec::IntoIter<[Identifier; 4]>>, Rev<smallvec::IntoIter<[Shared<Module>; 4]>>>;
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
fn into_iter(self) -> Self::IntoIter {
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
self.keys
|
self.keys
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@ -694,7 +694,7 @@ impl EvalState {
|
|||||||
self.scope_level == 0
|
self.scope_level == 0
|
||||||
}
|
}
|
||||||
/// Get a mutable reference to the current function resolution cache.
|
/// Get a mutable reference to the current function resolution cache.
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn fn_resolution_cache_mut(&mut self) -> &mut FnResolutionCache {
|
pub fn fn_resolution_cache_mut(&mut self) -> &mut FnResolutionCache {
|
||||||
if self.fn_resolution_caches.is_empty() {
|
if self.fn_resolution_caches.is_empty() {
|
||||||
@ -1235,13 +1235,14 @@ impl Engine {
|
|||||||
target: &mut Target,
|
target: &mut Target,
|
||||||
root: (&str, Position),
|
root: (&str, Position),
|
||||||
rhs: &Expr,
|
rhs: &Expr,
|
||||||
_terminate_chaining: bool,
|
terminate_chaining: bool,
|
||||||
idx_values: &mut StaticVec<ChainArgument>,
|
idx_values: &mut StaticVec<ChainArgument>,
|
||||||
chain_type: ChainType,
|
chain_type: ChainType,
|
||||||
level: usize,
|
level: usize,
|
||||||
new_val: Option<((Dynamic, Position), (Option<OpAssignment>, Position))>,
|
new_val: Option<((Dynamic, Position), (Option<OpAssignment>, Position))>,
|
||||||
) -> Result<(Dynamic, bool), Box<EvalAltResult>> {
|
) -> Result<(Dynamic, bool), Box<EvalAltResult>> {
|
||||||
let is_ref_mut = target.is_ref();
|
let is_ref_mut = target.is_ref();
|
||||||
|
let _terminate_chaining = terminate_chaining;
|
||||||
|
|
||||||
// Pop the last index value
|
// Pop the last index value
|
||||||
let idx_val = idx_values
|
let idx_val = idx_values
|
||||||
@ -1725,7 +1726,7 @@ impl Engine {
|
|||||||
this_ptr: &mut Option<&mut Dynamic>,
|
this_ptr: &mut Option<&mut Dynamic>,
|
||||||
expr: &Expr,
|
expr: &Expr,
|
||||||
terminate_chaining: bool,
|
terminate_chaining: bool,
|
||||||
_parent_chain_type: ChainType,
|
parent_chain_type: ChainType,
|
||||||
idx_values: &mut StaticVec<ChainArgument>,
|
idx_values: &mut StaticVec<ChainArgument>,
|
||||||
size: usize,
|
size: usize,
|
||||||
level: usize,
|
level: usize,
|
||||||
@ -1733,6 +1734,8 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
self.inc_operations(state, expr.position())?;
|
self.inc_operations(state, expr.position())?;
|
||||||
|
|
||||||
|
let _parent_chain_type = parent_chain_type;
|
||||||
|
|
||||||
match expr {
|
match expr {
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Expr::FnCall(x, _) if _parent_chain_type == ChainType::Dotting && !x.is_qualified() => {
|
Expr::FnCall(x, _) if _parent_chain_type == ChainType::Dotting && !x.is_qualified() => {
|
||||||
@ -1848,15 +1851,18 @@ impl Engine {
|
|||||||
state: &mut EvalState,
|
state: &mut EvalState,
|
||||||
lib: &[&Module],
|
lib: &[&Module],
|
||||||
target: &'t mut Dynamic,
|
target: &'t mut Dynamic,
|
||||||
mut idx: Dynamic,
|
idx: Dynamic,
|
||||||
idx_pos: Position,
|
idx_pos: Position,
|
||||||
_create: bool,
|
add_if_not_found: bool,
|
||||||
indexers: bool,
|
use_indexers: bool,
|
||||||
level: usize,
|
level: usize,
|
||||||
) -> Result<Target<'t>, Box<EvalAltResult>> {
|
) -> Result<Target<'t>, Box<EvalAltResult>> {
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
self.inc_operations(state, Position::NONE)?;
|
self.inc_operations(state, Position::NONE)?;
|
||||||
|
|
||||||
|
let mut idx = idx;
|
||||||
|
let _add_if_not_found = add_if_not_found;
|
||||||
|
|
||||||
match target {
|
match target {
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Dynamic(Union::Array(arr, _, _)) => {
|
Dynamic(Union::Array(arr, _, _)) => {
|
||||||
@ -1907,7 +1913,7 @@ impl Engine {
|
|||||||
self.make_type_mismatch_err::<ImmutableString>(idx.type_name(), idx_pos)
|
self.make_type_mismatch_err::<ImmutableString>(idx.type_name(), idx_pos)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
if _create && !map.contains_key(index.as_str()) {
|
if _add_if_not_found && !map.contains_key(index.as_str()) {
|
||||||
map.insert(index.clone().into(), Default::default());
|
map.insert(index.clone().into(), Default::default());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1988,7 +1994,7 @@ impl Engine {
|
|||||||
Ok(Target::StringChar(target, offset, ch.into()))
|
Ok(Target::StringChar(target, offset, ch.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
_ if indexers => {
|
_ if use_indexers => {
|
||||||
let args = &mut [target, &mut idx];
|
let args = &mut [target, &mut idx];
|
||||||
let hash_get = FnCallHashes::from_native(crate::calc_fn_hash(FN_IDX_GET, 2));
|
let hash_get = FnCallHashes::from_native(crate::calc_fn_hash(FN_IDX_GET, 2));
|
||||||
let idx_pos = Position::NONE;
|
let idx_pos = Position::NONE;
|
||||||
@ -2298,13 +2304,15 @@ impl Engine {
|
|||||||
op_pos: Position,
|
op_pos: Position,
|
||||||
target: &mut Target,
|
target: &mut Target,
|
||||||
root: (&str, Position),
|
root: (&str, Position),
|
||||||
mut new_val: Dynamic,
|
new_val: Dynamic,
|
||||||
) -> Result<(), Box<EvalAltResult>> {
|
) -> Result<(), Box<EvalAltResult>> {
|
||||||
if target.is_read_only() {
|
if target.is_read_only() {
|
||||||
// Assignment to constant variable
|
// Assignment to constant variable
|
||||||
return EvalAltResult::ErrorAssignmentToConstant(root.0.to_string(), root.1).into();
|
return EvalAltResult::ErrorAssignmentToConstant(root.0.to_string(), root.1).into();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut new_val = new_val;
|
||||||
|
|
||||||
if let Some(OpAssignment {
|
if let Some(OpAssignment {
|
||||||
hash_op_assign,
|
hash_op_assign,
|
||||||
hash_op,
|
hash_op,
|
||||||
|
@ -574,7 +574,7 @@ impl Engine {
|
|||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
pub fn register_indexer_get<T: Variant + Clone, X: Variant + Clone, V: Variant + Clone>(
|
pub fn register_indexer_get<T: Variant + Clone, X: Variant + Clone, V: Variant + Clone>(
|
||||||
&mut self,
|
&mut self,
|
||||||
get_fn: impl Fn(&mut T, X) -> V + SendSync + 'static,
|
get_fn: impl Fn(&mut T, X) -> V + SendSync + 'static,
|
||||||
@ -648,7 +648,7 @@ impl Engine {
|
|||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
pub fn register_indexer_get_result<
|
pub fn register_indexer_get_result<
|
||||||
T: Variant + Clone,
|
T: Variant + Clone,
|
||||||
X: Variant + Clone,
|
X: Variant + Clone,
|
||||||
@ -724,7 +724,7 @@ impl Engine {
|
|||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
pub fn register_indexer_set<T: Variant + Clone, X: Variant + Clone, V: Variant + Clone>(
|
pub fn register_indexer_set<T: Variant + Clone, X: Variant + Clone, V: Variant + Clone>(
|
||||||
&mut self,
|
&mut self,
|
||||||
set_fn: impl Fn(&mut T, X, V) + SendSync + 'static,
|
set_fn: impl Fn(&mut T, X, V) + SendSync + 'static,
|
||||||
@ -799,7 +799,7 @@ impl Engine {
|
|||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
pub fn register_indexer_set_result<
|
pub fn register_indexer_set_result<
|
||||||
T: Variant + Clone,
|
T: Variant + Clone,
|
||||||
X: Variant + Clone,
|
X: Variant + Clone,
|
||||||
|
@ -447,7 +447,7 @@ impl EvalAltResult {
|
|||||||
}
|
}
|
||||||
/// Consume the current [`EvalAltResult`] and return a new one with the specified [`Position`]
|
/// Consume the current [`EvalAltResult`] and return a new one with the specified [`Position`]
|
||||||
/// if the current position is [`Position::None`].
|
/// if the current position is [`Position::None`].
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) fn fill_position(mut self: Box<Self>, new_position: Position) -> Box<Self> {
|
pub(crate) fn fill_position(mut self: Box<Self>, new_position: Position) -> Box<Self> {
|
||||||
if self.position().is_none() {
|
if self.position().is_none() {
|
||||||
|
@ -611,7 +611,7 @@ impl Engine {
|
|||||||
hashes: FnCallHashes,
|
hashes: FnCallHashes,
|
||||||
args: &mut FnCallArgs,
|
args: &mut FnCallArgs,
|
||||||
is_ref_mut: bool,
|
is_ref_mut: bool,
|
||||||
_is_method_call: bool,
|
is_method_call: bool,
|
||||||
pos: Position,
|
pos: Position,
|
||||||
_capture_scope: Option<Scope>,
|
_capture_scope: Option<Scope>,
|
||||||
_level: usize,
|
_level: usize,
|
||||||
@ -625,6 +625,8 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
ensure_no_data_race(fn_name, args, is_ref_mut)?;
|
ensure_no_data_race(fn_name, args, is_ref_mut)?;
|
||||||
|
|
||||||
|
let _is_method_call = is_method_call;
|
||||||
|
|
||||||
// These may be redirected from method style calls.
|
// These may be redirected from method style calls.
|
||||||
match fn_name {
|
match fn_name {
|
||||||
// Handle type_of()
|
// Handle type_of()
|
||||||
|
@ -13,9 +13,19 @@ use std::{
|
|||||||
|
|
||||||
/// A general function pointer, which may carry additional (i.e. curried) argument values
|
/// A general function pointer, which may carry additional (i.e. curried) argument values
|
||||||
/// to be passed onto a function during a call.
|
/// to be passed onto a function during a call.
|
||||||
#[derive(Debug, Clone, Hash)]
|
#[derive(Clone, Hash)]
|
||||||
pub struct FnPtr(Identifier, StaticVec<Dynamic>);
|
pub struct FnPtr(Identifier, StaticVec<Dynamic>);
|
||||||
|
|
||||||
|
impl fmt::Debug for FnPtr {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
if !self.is_curried() {
|
||||||
|
write!(f, "Fn({})", self.fn_name())
|
||||||
|
} else {
|
||||||
|
f.debug_tuple("Fn").field(&self.0).field(&self.1).finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl FnPtr {
|
impl FnPtr {
|
||||||
/// Create a new function pointer.
|
/// Create a new function pointer.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -39,7 +39,7 @@ pub fn by_ref<T: Variant + Clone>(data: &mut Dynamic) -> DynamicWriteLock<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Dereference into value.
|
/// Dereference into value.
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn by_value<T: Variant + Clone>(data: &mut Dynamic) -> T {
|
pub fn by_value<T: Variant + Clone>(data: &mut Dynamic) -> T {
|
||||||
if TypeId::of::<T>() == TypeId::of::<&str>() {
|
if TypeId::of::<T>() == TypeId::of::<&str>() {
|
||||||
|
@ -455,7 +455,7 @@ impl Module {
|
|||||||
|
|
||||||
/// Get a reference to a namespace-qualified variable.
|
/// Get a reference to a namespace-qualified variable.
|
||||||
/// Name and Position in [`EvalAltResult`] are [`None`] and [`NONE`][Position::NONE] and must be set afterwards.
|
/// Name and Position in [`EvalAltResult`] are [`None`] and [`NONE`][Position::NONE] and must be set afterwards.
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
pub(crate) fn get_qualified_var(&self, hash_var: u64) -> Result<&Dynamic, Box<EvalAltResult>> {
|
pub(crate) fn get_qualified_var(&self, hash_var: u64) -> Result<&Dynamic, Box<EvalAltResult>> {
|
||||||
self.all_variables.get(&hash_var).ok_or_else(|| {
|
self.all_variables.get(&hash_var).ok_or_else(|| {
|
||||||
EvalAltResult::ErrorVariableNotFound(String::new(), Position::NONE).into()
|
EvalAltResult::ErrorVariableNotFound(String::new(), Position::NONE).into()
|
||||||
@ -497,7 +497,7 @@ impl Module {
|
|||||||
/// Get a shared reference to the script-defined function in the [`Module`] based on name
|
/// Get a shared reference to the script-defined function in the [`Module`] based on name
|
||||||
/// and number of parameters.
|
/// and number of parameters.
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_script_fn(
|
pub fn get_script_fn(
|
||||||
&self,
|
&self,
|
||||||
@ -965,7 +965,7 @@ impl Module {
|
|||||||
/// assert!(module.contains_fn(hash));
|
/// assert!(module.contains_fn(hash));
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
pub fn set_indexer_get_fn<ARGS, A, B, T, F>(&mut self, func: F) -> u64
|
pub fn set_indexer_get_fn<ARGS, A, B, T, F>(&mut self, func: F) -> u64
|
||||||
where
|
where
|
||||||
A: Variant + Clone,
|
A: Variant + Clone,
|
||||||
@ -1026,7 +1026,7 @@ impl Module {
|
|||||||
/// assert!(module.contains_fn(hash));
|
/// assert!(module.contains_fn(hash));
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
pub fn set_indexer_set_fn<ARGS, A, B, C, F>(&mut self, func: F) -> u64
|
pub fn set_indexer_set_fn<ARGS, A, B, C, F>(&mut self, func: F) -> u64
|
||||||
where
|
where
|
||||||
A: Variant + Clone,
|
A: Variant + Clone,
|
||||||
|
@ -686,7 +686,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Optimize an [expression][Expr].
|
/// Optimize an [expression][Expr].
|
||||||
fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, _chaining: bool) {
|
fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, chaining: bool) {
|
||||||
// These keywords are handled specially
|
// These keywords are handled specially
|
||||||
const DONT_EVAL_KEYWORDS: &[&str] = &[
|
const DONT_EVAL_KEYWORDS: &[&str] = &[
|
||||||
KEYWORD_PRINT, // side effects
|
KEYWORD_PRINT, // side effects
|
||||||
@ -694,6 +694,8 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, _chaining: bool) {
|
|||||||
KEYWORD_EVAL, // arbitrary scripts
|
KEYWORD_EVAL, // arbitrary scripts
|
||||||
];
|
];
|
||||||
|
|
||||||
|
let _chaining = chaining;
|
||||||
|
|
||||||
match expr {
|
match expr {
|
||||||
// {}
|
// {}
|
||||||
Expr::Stmt(x) if x.is_empty() => { state.set_dirty(); *expr = Expr::Unit(x.position()) }
|
Expr::Stmt(x) if x.is_empty() => { state.set_dirty(); *expr = Expr::Unit(x.position()) }
|
||||||
@ -1061,12 +1063,14 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, _chaining: bool) {
|
|||||||
|
|
||||||
/// Optimize a block of [statements][Stmt] at top level.
|
/// Optimize a block of [statements][Stmt] at top level.
|
||||||
fn optimize_top_level(
|
fn optimize_top_level(
|
||||||
mut statements: Vec<Stmt>,
|
statements: Vec<Stmt>,
|
||||||
engine: &Engine,
|
engine: &Engine,
|
||||||
scope: &Scope,
|
scope: &Scope,
|
||||||
lib: &[&Module],
|
lib: &[&Module],
|
||||||
optimization_level: OptimizationLevel,
|
optimization_level: OptimizationLevel,
|
||||||
) -> Vec<Stmt> {
|
) -> Vec<Stmt> {
|
||||||
|
let mut statements = statements;
|
||||||
|
|
||||||
// If optimization level is None then skip optimizing
|
// If optimization level is None then skip optimizing
|
||||||
if optimization_level == OptimizationLevel::None {
|
if optimization_level == OptimizationLevel::None {
|
||||||
statements.shrink_to_fit();
|
statements.shrink_to_fit();
|
||||||
@ -1093,8 +1097,8 @@ fn optimize_top_level(
|
|||||||
pub fn optimize_into_ast(
|
pub fn optimize_into_ast(
|
||||||
engine: &Engine,
|
engine: &Engine,
|
||||||
scope: &Scope,
|
scope: &Scope,
|
||||||
mut statements: Vec<Stmt>,
|
statements: Vec<Stmt>,
|
||||||
_functions: Vec<crate::Shared<crate::ast::ScriptFnDef>>,
|
functions: Vec<crate::Shared<crate::ast::ScriptFnDef>>,
|
||||||
optimization_level: OptimizationLevel,
|
optimization_level: OptimizationLevel,
|
||||||
) -> AST {
|
) -> AST {
|
||||||
let level = if cfg!(feature = "no_optimize") {
|
let level = if cfg!(feature = "no_optimize") {
|
||||||
@ -1103,6 +1107,9 @@ pub fn optimize_into_ast(
|
|||||||
optimization_level
|
optimization_level
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let mut statements = statements;
|
||||||
|
let _functions = functions;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
let lib = {
|
let lib = {
|
||||||
let mut module = Module::new();
|
let mut module = Module::new();
|
||||||
|
@ -753,17 +753,19 @@ mod array_functions {
|
|||||||
#[rhai_fn(name = "==", return_raw, pure)]
|
#[rhai_fn(name = "==", return_raw, pure)]
|
||||||
pub fn equals(
|
pub fn equals(
|
||||||
ctx: NativeCallContext,
|
ctx: NativeCallContext,
|
||||||
array: &mut Array,
|
array1: &mut Array,
|
||||||
mut array2: Array,
|
array2: Array,
|
||||||
) -> Result<bool, Box<EvalAltResult>> {
|
) -> Result<bool, Box<EvalAltResult>> {
|
||||||
if array.len() != array2.len() {
|
if array1.len() != array2.len() {
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
if array.is_empty() {
|
if array1.is_empty() {
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (a1, a2) in array.iter_mut().zip(array2.iter_mut()) {
|
let mut array2 = array2;
|
||||||
|
|
||||||
|
for (a1, a2) in array1.iter_mut().zip(array2.iter_mut()) {
|
||||||
if !ctx
|
if !ctx
|
||||||
.call_fn_dynamic_raw(OP_EQUALS, true, &mut [a1, a2])
|
.call_fn_dynamic_raw(OP_EQUALS, true, &mut [a1, a2])
|
||||||
.or_else(|err| match *err {
|
.or_else(|err| match *err {
|
||||||
@ -791,9 +793,9 @@ mod array_functions {
|
|||||||
#[rhai_fn(name = "!=", return_raw, pure)]
|
#[rhai_fn(name = "!=", return_raw, pure)]
|
||||||
pub fn not_equals(
|
pub fn not_equals(
|
||||||
ctx: NativeCallContext,
|
ctx: NativeCallContext,
|
||||||
array: &mut Array,
|
array1: &mut Array,
|
||||||
array2: Array,
|
array2: Array,
|
||||||
) -> Result<bool, Box<EvalAltResult>> {
|
) -> Result<bool, Box<EvalAltResult>> {
|
||||||
equals(ctx, array, array2).map(|r| !r)
|
equals(ctx, array1, array2).map(|r| !r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,15 +10,15 @@ def_package!(crate:BasicFnPackage:"Basic Fn functions.", lib, {
|
|||||||
#[export_module]
|
#[export_module]
|
||||||
mod fn_ptr_functions {
|
mod fn_ptr_functions {
|
||||||
#[rhai_fn(name = "name", get = "name", pure)]
|
#[rhai_fn(name = "name", get = "name", pure)]
|
||||||
pub fn name(f: &mut FnPtr) -> ImmutableString {
|
pub fn name(fn_ptr: &mut FnPtr) -> ImmutableString {
|
||||||
f.fn_name_raw().into()
|
fn_ptr.fn_name_raw().into()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
pub mod functions {
|
pub mod functions {
|
||||||
#[rhai_fn(name = "is_anonymous", get = "is_anonymous", pure)]
|
#[rhai_fn(name = "is_anonymous", get = "is_anonymous", pure)]
|
||||||
pub fn is_anonymous(f: &mut FnPtr) -> bool {
|
pub fn is_anonymous(fn_ptr: &mut FnPtr) -> bool {
|
||||||
f.is_anonymous()
|
fn_ptr.is_anonymous()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,9 +34,10 @@ mod map_functions {
|
|||||||
map.extend(map2.into_iter());
|
map.extend(map2.into_iter());
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "+")]
|
#[rhai_fn(name = "+")]
|
||||||
pub fn merge(mut map: Map, map2: Map) -> Map {
|
pub fn merge(map1: Map, map2: Map) -> Map {
|
||||||
map.extend(map2.into_iter());
|
let mut map1 = map1;
|
||||||
map
|
map1.extend(map2.into_iter());
|
||||||
|
map1
|
||||||
}
|
}
|
||||||
pub fn fill_with(map: &mut Map, map2: Map) {
|
pub fn fill_with(map: &mut Map, map2: Map) {
|
||||||
map2.into_iter().for_each(|(key, value)| {
|
map2.into_iter().for_each(|(key, value)| {
|
||||||
@ -46,17 +47,19 @@ mod map_functions {
|
|||||||
#[rhai_fn(name = "==", return_raw, pure)]
|
#[rhai_fn(name = "==", return_raw, pure)]
|
||||||
pub fn equals(
|
pub fn equals(
|
||||||
ctx: NativeCallContext,
|
ctx: NativeCallContext,
|
||||||
map: &mut Map,
|
map1: &mut Map,
|
||||||
mut map2: Map,
|
map2: Map,
|
||||||
) -> Result<bool, Box<EvalAltResult>> {
|
) -> Result<bool, Box<EvalAltResult>> {
|
||||||
if map.len() != map2.len() {
|
if map1.len() != map2.len() {
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
if map.is_empty() {
|
if map1.is_empty() {
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (m1, v1) in map.iter_mut() {
|
let mut map2 = map2;
|
||||||
|
|
||||||
|
for (m1, v1) in map1.iter_mut() {
|
||||||
if let Some(v2) = map2.get_mut(m1) {
|
if let Some(v2) = map2.get_mut(m1) {
|
||||||
let equals = ctx
|
let equals = ctx
|
||||||
.call_fn_dynamic_raw(OP_EQUALS, true, &mut [v1, v2])
|
.call_fn_dynamic_raw(OP_EQUALS, true, &mut [v1, v2])
|
||||||
@ -75,10 +78,10 @@ mod map_functions {
|
|||||||
#[rhai_fn(name = "!=", return_raw, pure)]
|
#[rhai_fn(name = "!=", return_raw, pure)]
|
||||||
pub fn not_equals(
|
pub fn not_equals(
|
||||||
ctx: NativeCallContext,
|
ctx: NativeCallContext,
|
||||||
map: &mut Map,
|
map1: &mut Map,
|
||||||
map2: Map,
|
map2: Map,
|
||||||
) -> Result<bool, Box<EvalAltResult>> {
|
) -> Result<bool, Box<EvalAltResult>> {
|
||||||
equals(ctx, map, map2).map(|r| !r)
|
equals(ctx, map1, map2).map(|r| !r)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
@ -112,7 +112,7 @@ def_package!(crate:BasicMathPackage:"Basic mathematic functions.", lib, {
|
|||||||
#[export_module]
|
#[export_module]
|
||||||
mod int_functions {
|
mod int_functions {
|
||||||
#[rhai_fn(name = "parse_int", return_raw)]
|
#[rhai_fn(name = "parse_int", return_raw)]
|
||||||
pub fn parse_int_radix(s: &str, radix: INT) -> Result<INT, Box<EvalAltResult>> {
|
pub fn parse_int_radix(string: &str, radix: INT) -> Result<INT, Box<EvalAltResult>> {
|
||||||
if !(2..=36).contains(&radix) {
|
if !(2..=36).contains(&radix) {
|
||||||
return EvalAltResult::ErrorArithmetic(
|
return EvalAltResult::ErrorArithmetic(
|
||||||
format!("Invalid radix: '{}'", radix),
|
format!("Invalid radix: '{}'", radix),
|
||||||
@ -121,17 +121,17 @@ mod int_functions {
|
|||||||
.into();
|
.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
INT::from_str_radix(s.trim(), radix as u32).map_err(|err| {
|
INT::from_str_radix(string.trim(), radix as u32).map_err(|err| {
|
||||||
EvalAltResult::ErrorArithmetic(
|
EvalAltResult::ErrorArithmetic(
|
||||||
format!("Error parsing integer number '{}': {}", s, err),
|
format!("Error parsing integer number '{}': {}", string, err),
|
||||||
Position::NONE,
|
Position::NONE,
|
||||||
)
|
)
|
||||||
.into()
|
.into()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "parse_int", return_raw)]
|
#[rhai_fn(name = "parse_int", return_raw)]
|
||||||
pub fn parse_int(s: &str) -> Result<INT, Box<EvalAltResult>> {
|
pub fn parse_int(string: &str) -> Result<INT, Box<EvalAltResult>> {
|
||||||
parse_int_radix(s, 10)
|
parse_int_radix(string, 10)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,10 +283,10 @@ mod float_functions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[rhai_fn(return_raw)]
|
#[rhai_fn(return_raw)]
|
||||||
pub fn parse_float(s: &str) -> Result<FLOAT, Box<EvalAltResult>> {
|
pub fn parse_float(string: &str) -> Result<FLOAT, Box<EvalAltResult>> {
|
||||||
s.trim().parse::<FLOAT>().map_err(|err| {
|
string.trim().parse::<FLOAT>().map_err(|err| {
|
||||||
EvalAltResult::ErrorArithmetic(
|
EvalAltResult::ErrorArithmetic(
|
||||||
format!("Error parsing floating-point number '{}': {}", s, err),
|
format!("Error parsing floating-point number '{}': {}", string, err),
|
||||||
Position::NONE,
|
Position::NONE,
|
||||||
)
|
)
|
||||||
.into()
|
.into()
|
||||||
@ -427,12 +427,12 @@ mod decimal_functions {
|
|||||||
x.fract()
|
x.fract()
|
||||||
}
|
}
|
||||||
#[rhai_fn(return_raw)]
|
#[rhai_fn(return_raw)]
|
||||||
pub fn parse_decimal(s: &str) -> Result<Decimal, Box<EvalAltResult>> {
|
pub fn parse_decimal(string: &str) -> Result<Decimal, Box<EvalAltResult>> {
|
||||||
Decimal::from_str(s)
|
Decimal::from_str(string)
|
||||||
.or_else(|_| Decimal::from_scientific(s))
|
.or_else(|_| Decimal::from_scientific(string))
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
EvalAltResult::ErrorArithmetic(
|
EvalAltResult::ErrorArithmetic(
|
||||||
format!("Error parsing decimal number '{}': {}", s, err),
|
format!("Error parsing decimal number '{}': {}", string, err),
|
||||||
Position::NONE,
|
Position::NONE,
|
||||||
)
|
)
|
||||||
.into()
|
.into()
|
||||||
|
@ -50,12 +50,13 @@ mod string_functions {
|
|||||||
string1 + string2
|
string1 + string2
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "+", name = "append")]
|
#[rhai_fn(name = "+", name = "append")]
|
||||||
pub fn add_append_char(string: ImmutableString, ch: char) -> ImmutableString {
|
pub fn add_append_char(string: ImmutableString, character: char) -> ImmutableString {
|
||||||
string + ch
|
string + character
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rhai_fn(name = "+", name = "append")]
|
#[rhai_fn(name = "+", name = "append")]
|
||||||
pub fn add_append_unit(string: ImmutableString, _item: ()) -> ImmutableString {
|
pub fn add_append_unit(string: ImmutableString, item: ()) -> ImmutableString {
|
||||||
|
let _item = item;
|
||||||
string
|
string
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "+")]
|
#[rhai_fn(name = "+")]
|
||||||
@ -369,11 +370,13 @@ mod string_functions {
|
|||||||
|
|
||||||
#[rhai_fn(return_raw)]
|
#[rhai_fn(return_raw)]
|
||||||
pub fn pad(
|
pub fn pad(
|
||||||
_ctx: NativeCallContext,
|
ctx: NativeCallContext,
|
||||||
string: &mut ImmutableString,
|
string: &mut ImmutableString,
|
||||||
len: INT,
|
len: INT,
|
||||||
character: char,
|
character: char,
|
||||||
) -> Result<(), Box<crate::EvalAltResult>> {
|
) -> Result<(), Box<crate::EvalAltResult>> {
|
||||||
|
let _ctx = ctx;
|
||||||
|
|
||||||
// Check if string will be over max size limit
|
// Check if string will be over max size limit
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
if _ctx.engine().max_string_size() > 0 && len as usize > _ctx.engine().max_string_size() {
|
if _ctx.engine().max_string_size() > 0 && len as usize > _ctx.engine().max_string_size() {
|
||||||
@ -411,11 +414,13 @@ mod string_functions {
|
|||||||
}
|
}
|
||||||
#[rhai_fn(name = "pad", return_raw)]
|
#[rhai_fn(name = "pad", return_raw)]
|
||||||
pub fn pad_with_string(
|
pub fn pad_with_string(
|
||||||
_ctx: NativeCallContext,
|
ctx: NativeCallContext,
|
||||||
string: &mut ImmutableString,
|
string: &mut ImmutableString,
|
||||||
len: INT,
|
len: INT,
|
||||||
padding: &str,
|
padding: &str,
|
||||||
) -> Result<(), Box<crate::EvalAltResult>> {
|
) -> Result<(), Box<crate::EvalAltResult>> {
|
||||||
|
let _ctx = ctx;
|
||||||
|
|
||||||
// Check if string will be over max size limit
|
// Check if string will be over max size limit
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
if _ctx.engine().max_string_size() > 0 && len as usize > _ctx.engine().max_string_size() {
|
if _ctx.engine().max_string_size() > 0 && len as usize > _ctx.engine().max_string_size() {
|
||||||
|
@ -54,20 +54,20 @@ mod time_functions {
|
|||||||
|
|
||||||
#[rhai_fn(return_raw, name = "-")]
|
#[rhai_fn(return_raw, name = "-")]
|
||||||
pub fn time_diff(
|
pub fn time_diff(
|
||||||
timestamp: Instant,
|
timestamp1: Instant,
|
||||||
timestamp2: Instant,
|
timestamp2: Instant,
|
||||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
return Ok(if timestamp2 > timestamp {
|
return Ok(if timestamp2 > timestamp1 {
|
||||||
-(timestamp2 - timestamp).as_secs_f64() as FLOAT
|
-(timestamp2 - timestamp1).as_secs_f64() as FLOAT
|
||||||
} else {
|
} else {
|
||||||
(timestamp - timestamp2).as_secs_f64() as FLOAT
|
(timestamp1 - timestamp2).as_secs_f64() as FLOAT
|
||||||
}
|
}
|
||||||
.into());
|
.into());
|
||||||
|
|
||||||
#[cfg(feature = "no_float")]
|
#[cfg(feature = "no_float")]
|
||||||
if timestamp2 > timestamp {
|
if timestamp2 > timestamp1 {
|
||||||
let seconds = (timestamp2 - timestamp).as_secs();
|
let seconds = (timestamp2 - timestamp1).as_secs();
|
||||||
|
|
||||||
if cfg!(not(feature = "unchecked")) && seconds > (MAX_INT as u64) {
|
if cfg!(not(feature = "unchecked")) && seconds > (MAX_INT as u64) {
|
||||||
Err(make_arithmetic_err(format!(
|
Err(make_arithmetic_err(format!(
|
||||||
@ -78,7 +78,7 @@ mod time_functions {
|
|||||||
Ok((-(seconds as INT)).into())
|
Ok((-(seconds as INT)).into())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let seconds = (timestamp - timestamp2).as_secs();
|
let seconds = (timestamp1 - timestamp2).as_secs();
|
||||||
|
|
||||||
if cfg!(not(feature = "unchecked")) && seconds > (MAX_INT as u64) {
|
if cfg!(not(feature = "unchecked")) && seconds > (MAX_INT as u64) {
|
||||||
Err(make_arithmetic_err(format!(
|
Err(make_arithmetic_err(format!(
|
||||||
@ -225,27 +225,27 @@ mod time_functions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[rhai_fn(name = "==")]
|
#[rhai_fn(name = "==")]
|
||||||
pub fn eq(timestamp: Instant, timestamp2: Instant) -> bool {
|
pub fn eq(timestamp1: Instant, timestamp2: Instant) -> bool {
|
||||||
timestamp == timestamp2
|
timestamp1 == timestamp2
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "!=")]
|
#[rhai_fn(name = "!=")]
|
||||||
pub fn ne(timestamp: Instant, timestamp2: Instant) -> bool {
|
pub fn ne(timestamp1: Instant, timestamp2: Instant) -> bool {
|
||||||
timestamp != timestamp2
|
timestamp1 != timestamp2
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "<")]
|
#[rhai_fn(name = "<")]
|
||||||
pub fn lt(timestamp: Instant, timestamp2: Instant) -> bool {
|
pub fn lt(timestamp1: Instant, timestamp2: Instant) -> bool {
|
||||||
timestamp < timestamp2
|
timestamp1 < timestamp2
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "<=")]
|
#[rhai_fn(name = "<=")]
|
||||||
pub fn lte(timestamp: Instant, timestamp2: Instant) -> bool {
|
pub fn lte(timestamp1: Instant, timestamp2: Instant) -> bool {
|
||||||
timestamp <= timestamp2
|
timestamp1 <= timestamp2
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = ">")]
|
#[rhai_fn(name = ">")]
|
||||||
pub fn gt(timestamp: Instant, timestamp2: Instant) -> bool {
|
pub fn gt(timestamp1: Instant, timestamp2: Instant) -> bool {
|
||||||
timestamp > timestamp2
|
timestamp1 > timestamp2
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = ">=")]
|
#[rhai_fn(name = ">=")]
|
||||||
pub fn gte(timestamp: Instant, timestamp2: Instant) -> bool {
|
pub fn gte(timestamp1: Instant, timestamp2: Instant) -> bool {
|
||||||
timestamp >= timestamp2
|
timestamp1 >= timestamp2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
162
src/parse.rs
162
src/parse.rs
@ -142,8 +142,9 @@ impl<'e> ParseState<'e> {
|
|||||||
///
|
///
|
||||||
/// Return `None` when the variable name is not found in the `stack`.
|
/// Return `None` when the variable name is not found in the `stack`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn access_var(&mut self, name: &str, _pos: Position) -> Option<NonZeroUsize> {
|
pub fn access_var(&mut self, name: &str, pos: Position) -> Option<NonZeroUsize> {
|
||||||
let mut barrier = false;
|
let mut barrier = false;
|
||||||
|
let _pos = pos;
|
||||||
|
|
||||||
let index = self
|
let index = self
|
||||||
.stack
|
.stack
|
||||||
@ -188,7 +189,7 @@ impl<'e> ParseState<'e> {
|
|||||||
///
|
///
|
||||||
/// Panics when called under `no_module`.
|
/// Panics when called under `no_module`.
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn find_module(&self, name: &str) -> Option<NonZeroUsize> {
|
pub fn find_module(&self, name: &str) -> Option<NonZeroUsize> {
|
||||||
self.modules
|
self.modules
|
||||||
@ -324,7 +325,7 @@ impl Expr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Make sure that the next expression is not a statement expression (i.e. wrapped in `{}`).
|
/// Make sure that the next expression is not a statement expression (i.e. wrapped in `{}`).
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
fn ensure_not_statement_expr(input: &mut TokenStream, type_name: &str) -> Result<(), ParseError> {
|
fn ensure_not_statement_expr(input: &mut TokenStream, type_name: &str) -> Result<(), ParseError> {
|
||||||
match input.peek().expect(NEVER_ENDS) {
|
match input.peek().expect(NEVER_ENDS) {
|
||||||
(Token::LeftBrace, pos) => Err(PERR::ExprExpected(type_name.to_string()).into_err(*pos)),
|
(Token::LeftBrace, pos) => Err(PERR::ExprExpected(type_name.to_string()).into_err(*pos)),
|
||||||
@ -333,7 +334,7 @@ fn ensure_not_statement_expr(input: &mut TokenStream, type_name: &str) -> Result
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Make sure that the next expression is not a mis-typed assignment (i.e. `a = b` instead of `a == b`).
|
/// Make sure that the next expression is not a mis-typed assignment (i.e. `a = b` instead of `a == b`).
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
fn ensure_not_assignment(input: &mut TokenStream) -> Result<(), ParseError> {
|
fn ensure_not_assignment(input: &mut TokenStream) -> Result<(), ParseError> {
|
||||||
match input.peek().expect(NEVER_ENDS) {
|
match input.peek().expect(NEVER_ENDS) {
|
||||||
(Token::Equals, pos) => Err(LexError::ImproperSymbol(
|
(Token::Equals, pos) => Err(LexError::ImproperSymbol(
|
||||||
@ -393,8 +394,10 @@ fn parse_paren_expr(
|
|||||||
input: &mut TokenStream,
|
input: &mut TokenStream,
|
||||||
state: &mut ParseState,
|
state: &mut ParseState,
|
||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
mut settings: ParseSettings,
|
settings: ParseSettings,
|
||||||
) -> Result<Expr, ParseError> {
|
) -> Result<Expr, ParseError> {
|
||||||
|
let mut settings = settings;
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
@ -428,7 +431,7 @@ fn parse_fn_call(
|
|||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
id: Identifier,
|
id: Identifier,
|
||||||
capture: bool,
|
capture: bool,
|
||||||
mut namespace: Option<NamespaceRef>,
|
namespace: Option<NamespaceRef>,
|
||||||
settings: ParseSettings,
|
settings: ParseSettings,
|
||||||
) -> Result<Expr, ParseError> {
|
) -> Result<Expr, ParseError> {
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
@ -436,6 +439,7 @@ fn parse_fn_call(
|
|||||||
|
|
||||||
let (token, token_pos) = input.peek().expect(NEVER_ENDS);
|
let (token, token_pos) = input.peek().expect(NEVER_ENDS);
|
||||||
|
|
||||||
|
let mut namespace = namespace;
|
||||||
let mut args = StaticVec::new();
|
let mut args = StaticVec::new();
|
||||||
|
|
||||||
match token {
|
match token {
|
||||||
@ -565,8 +569,10 @@ fn parse_index_chain(
|
|||||||
state: &mut ParseState,
|
state: &mut ParseState,
|
||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
lhs: Expr,
|
lhs: Expr,
|
||||||
mut settings: ParseSettings,
|
settings: ParseSettings,
|
||||||
) -> Result<Expr, ParseError> {
|
) -> Result<Expr, ParseError> {
|
||||||
|
let mut settings = settings;
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
@ -726,8 +732,10 @@ fn parse_array_literal(
|
|||||||
input: &mut TokenStream,
|
input: &mut TokenStream,
|
||||||
state: &mut ParseState,
|
state: &mut ParseState,
|
||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
mut settings: ParseSettings,
|
settings: ParseSettings,
|
||||||
) -> Result<Expr, ParseError> {
|
) -> Result<Expr, ParseError> {
|
||||||
|
let mut settings = settings;
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
@ -798,8 +806,10 @@ fn parse_map_literal(
|
|||||||
input: &mut TokenStream,
|
input: &mut TokenStream,
|
||||||
state: &mut ParseState,
|
state: &mut ParseState,
|
||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
mut settings: ParseSettings,
|
settings: ParseSettings,
|
||||||
) -> Result<Expr, ParseError> {
|
) -> Result<Expr, ParseError> {
|
||||||
|
let mut settings = settings;
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
@ -914,8 +924,10 @@ fn parse_switch(
|
|||||||
input: &mut TokenStream,
|
input: &mut TokenStream,
|
||||||
state: &mut ParseState,
|
state: &mut ParseState,
|
||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
mut settings: ParseSettings,
|
settings: ParseSettings,
|
||||||
) -> Result<Stmt, ParseError> {
|
) -> Result<Stmt, ParseError> {
|
||||||
|
let mut settings = settings;
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
@ -1059,8 +1071,10 @@ fn parse_primary(
|
|||||||
input: &mut TokenStream,
|
input: &mut TokenStream,
|
||||||
state: &mut ParseState,
|
state: &mut ParseState,
|
||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
mut settings: ParseSettings,
|
settings: ParseSettings,
|
||||||
) -> Result<Expr, ParseError> {
|
) -> Result<Expr, ParseError> {
|
||||||
|
let mut settings = settings;
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
@ -1439,8 +1453,10 @@ fn parse_unary(
|
|||||||
input: &mut TokenStream,
|
input: &mut TokenStream,
|
||||||
state: &mut ParseState,
|
state: &mut ParseState,
|
||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
mut settings: ParseSettings,
|
settings: ParseSettings,
|
||||||
) -> Result<Expr, ParseError> {
|
) -> Result<Expr, ParseError> {
|
||||||
|
let mut settings = settings;
|
||||||
|
|
||||||
let (token, token_pos) = input.peek().expect(NEVER_ENDS);
|
let (token, token_pos) = input.peek().expect(NEVER_ENDS);
|
||||||
settings.pos = *token_pos;
|
settings.pos = *token_pos;
|
||||||
|
|
||||||
@ -1623,8 +1639,10 @@ fn parse_op_assignment_stmt(
|
|||||||
state: &mut ParseState,
|
state: &mut ParseState,
|
||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
lhs: Expr,
|
lhs: Expr,
|
||||||
mut settings: ParseSettings,
|
settings: ParseSettings,
|
||||||
) -> Result<Stmt, ParseError> {
|
) -> Result<Stmt, ParseError> {
|
||||||
|
let mut settings = settings;
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
@ -1679,18 +1697,27 @@ fn make_dot_expr(
|
|||||||
(lhs, prop @ Expr::Property(_)) => {
|
(lhs, prop @ Expr::Property(_)) => {
|
||||||
Expr::Dot(BinaryExpr { lhs, rhs: prop }.into(), false, op_pos)
|
Expr::Dot(BinaryExpr { lhs, rhs: prop }.into(), false, op_pos)
|
||||||
}
|
}
|
||||||
// lhs.dot_lhs.dot_rhs
|
// lhs.dot_lhs.dot_rhs or lhs.dot_lhs[idx_rhs]
|
||||||
(lhs, Expr::Dot(x, _, pos)) => match x.lhs {
|
(lhs, rhs @ Expr::Dot(_, _, _)) | (lhs, rhs @ Expr::Index(_, _, _)) => {
|
||||||
|
let (x, term, pos, is_dot) = match rhs {
|
||||||
|
Expr::Dot(x, term, pos) => (x, term, pos, true),
|
||||||
|
Expr::Index(x, term, pos) => (x, term, pos, false),
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
match x.lhs {
|
||||||
Expr::Variable(_, _, _) | Expr::Property(_) => {
|
Expr::Variable(_, _, _) | Expr::Property(_) => {
|
||||||
let rhs = Expr::Dot(
|
let new_lhs = BinaryExpr {
|
||||||
BinaryExpr {
|
|
||||||
lhs: x.lhs.into_property(state),
|
lhs: x.lhs.into_property(state),
|
||||||
rhs: x.rhs,
|
rhs: x.rhs,
|
||||||
}
|
}
|
||||||
.into(),
|
.into();
|
||||||
false,
|
|
||||||
pos,
|
let rhs = if is_dot {
|
||||||
);
|
Expr::Dot(new_lhs, term, pos)
|
||||||
|
} else {
|
||||||
|
Expr::Index(new_lhs, term, pos)
|
||||||
|
};
|
||||||
Expr::Dot(BinaryExpr { lhs, rhs }.into(), false, op_pos)
|
Expr::Dot(BinaryExpr { lhs, rhs }.into(), false, op_pos)
|
||||||
}
|
}
|
||||||
Expr::FnCall(mut func, func_pos) => {
|
Expr::FnCall(mut func, func_pos) => {
|
||||||
@ -1700,31 +1727,21 @@ fn make_dot_expr(
|
|||||||
calc_fn_hash(&func.name, func.args.len() + 1),
|
calc_fn_hash(&func.name, func.args.len() + 1),
|
||||||
);
|
);
|
||||||
|
|
||||||
let rhs = Expr::Dot(
|
let new_lhs = BinaryExpr {
|
||||||
BinaryExpr {
|
|
||||||
lhs: Expr::FnCall(func, func_pos),
|
lhs: Expr::FnCall(func, func_pos),
|
||||||
rhs: x.rhs,
|
rhs: x.rhs,
|
||||||
}
|
}
|
||||||
.into(),
|
.into();
|
||||||
false,
|
|
||||||
pos,
|
let rhs = if is_dot {
|
||||||
);
|
Expr::Dot(new_lhs, term, pos)
|
||||||
|
} else {
|
||||||
|
Expr::Index(new_lhs, term, pos)
|
||||||
|
};
|
||||||
Expr::Dot(BinaryExpr { lhs, rhs }.into(), false, op_pos)
|
Expr::Dot(BinaryExpr { lhs, rhs }.into(), false, op_pos)
|
||||||
}
|
}
|
||||||
_ => unreachable!("invalid dot expression: {:?}", x.lhs),
|
_ => unreachable!("invalid dot expression: {:?}", x.lhs),
|
||||||
},
|
|
||||||
// lhs.idx_lhs[idx_rhs]
|
|
||||||
(lhs, Expr::Index(x, term, pos)) => {
|
|
||||||
let rhs = Expr::Index(
|
|
||||||
BinaryExpr {
|
|
||||||
lhs: x.lhs.into_property(state),
|
|
||||||
rhs: x.rhs,
|
|
||||||
}
|
}
|
||||||
.into(),
|
|
||||||
term,
|
|
||||||
pos,
|
|
||||||
);
|
|
||||||
Expr::Dot(BinaryExpr { lhs, rhs }.into(), false, op_pos)
|
|
||||||
}
|
}
|
||||||
// lhs.nnn::func(...)
|
// lhs.nnn::func(...)
|
||||||
(_, Expr::FnCall(x, _)) if x.is_qualified() => {
|
(_, Expr::FnCall(x, _)) if x.is_qualified() => {
|
||||||
@ -1774,8 +1791,10 @@ fn parse_binary_op(
|
|||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
parent_precedence: Option<Precedence>,
|
parent_precedence: Option<Precedence>,
|
||||||
lhs: Expr,
|
lhs: Expr,
|
||||||
mut settings: ParseSettings,
|
settings: ParseSettings,
|
||||||
) -> Result<Expr, ParseError> {
|
) -> Result<Expr, ParseError> {
|
||||||
|
let mut settings = settings;
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
@ -1955,11 +1974,12 @@ fn parse_custom_syntax(
|
|||||||
input: &mut TokenStream,
|
input: &mut TokenStream,
|
||||||
state: &mut ParseState,
|
state: &mut ParseState,
|
||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
mut settings: ParseSettings,
|
settings: ParseSettings,
|
||||||
key: &str,
|
key: &str,
|
||||||
syntax: &CustomSyntax,
|
syntax: &CustomSyntax,
|
||||||
pos: Position,
|
pos: Position,
|
||||||
) -> Result<Expr, ParseError> {
|
) -> Result<Expr, ParseError> {
|
||||||
|
let mut settings = settings;
|
||||||
let mut keywords: StaticVec<Expr> = Default::default();
|
let mut keywords: StaticVec<Expr> = Default::default();
|
||||||
let mut segments: StaticVec<_> = Default::default();
|
let mut segments: StaticVec<_> = Default::default();
|
||||||
let mut tokens: StaticVec<_> = Default::default();
|
let mut tokens: StaticVec<_> = Default::default();
|
||||||
@ -2101,8 +2121,10 @@ fn parse_expr(
|
|||||||
input: &mut TokenStream,
|
input: &mut TokenStream,
|
||||||
state: &mut ParseState,
|
state: &mut ParseState,
|
||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
mut settings: ParseSettings,
|
settings: ParseSettings,
|
||||||
) -> Result<Expr, ParseError> {
|
) -> Result<Expr, ParseError> {
|
||||||
|
let mut settings = settings;
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
@ -2144,8 +2166,10 @@ fn parse_if(
|
|||||||
input: &mut TokenStream,
|
input: &mut TokenStream,
|
||||||
state: &mut ParseState,
|
state: &mut ParseState,
|
||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
mut settings: ParseSettings,
|
settings: ParseSettings,
|
||||||
) -> Result<Stmt, ParseError> {
|
) -> Result<Stmt, ParseError> {
|
||||||
|
let mut settings = settings;
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
@ -2183,8 +2207,10 @@ fn parse_while_loop(
|
|||||||
input: &mut TokenStream,
|
input: &mut TokenStream,
|
||||||
state: &mut ParseState,
|
state: &mut ParseState,
|
||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
mut settings: ParseSettings,
|
settings: ParseSettings,
|
||||||
) -> Result<Stmt, ParseError> {
|
) -> Result<Stmt, ParseError> {
|
||||||
|
let mut settings = settings;
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
@ -2212,8 +2238,10 @@ fn parse_do(
|
|||||||
input: &mut TokenStream,
|
input: &mut TokenStream,
|
||||||
state: &mut ParseState,
|
state: &mut ParseState,
|
||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
mut settings: ParseSettings,
|
settings: ParseSettings,
|
||||||
) -> Result<Stmt, ParseError> {
|
) -> Result<Stmt, ParseError> {
|
||||||
|
let mut settings = settings;
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
@ -2254,8 +2282,10 @@ fn parse_for(
|
|||||||
input: &mut TokenStream,
|
input: &mut TokenStream,
|
||||||
state: &mut ParseState,
|
state: &mut ParseState,
|
||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
mut settings: ParseSettings,
|
settings: ParseSettings,
|
||||||
) -> Result<Stmt, ParseError> {
|
) -> Result<Stmt, ParseError> {
|
||||||
|
let mut settings = settings;
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
@ -2353,9 +2383,11 @@ fn parse_let(
|
|||||||
state: &mut ParseState,
|
state: &mut ParseState,
|
||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
var_type: AccessMode,
|
var_type: AccessMode,
|
||||||
export: bool,
|
is_export: bool,
|
||||||
mut settings: ParseSettings,
|
settings: ParseSettings,
|
||||||
) -> Result<Stmt, ParseError> {
|
) -> Result<Stmt, ParseError> {
|
||||||
|
let mut settings = settings;
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
@ -2381,7 +2413,7 @@ fn parse_let(
|
|||||||
|
|
||||||
state.stack.push((name, var_type));
|
state.stack.push((name, var_type));
|
||||||
|
|
||||||
let export = if export {
|
let export = if is_export {
|
||||||
AST_OPTION_EXPORTED
|
AST_OPTION_EXPORTED
|
||||||
} else {
|
} else {
|
||||||
AST_OPTION_NONE
|
AST_OPTION_NONE
|
||||||
@ -2406,8 +2438,10 @@ fn parse_import(
|
|||||||
input: &mut TokenStream,
|
input: &mut TokenStream,
|
||||||
state: &mut ParseState,
|
state: &mut ParseState,
|
||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
mut settings: ParseSettings,
|
settings: ParseSettings,
|
||||||
) -> Result<Stmt, ParseError> {
|
) -> Result<Stmt, ParseError> {
|
||||||
|
let mut settings = settings;
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
@ -2446,8 +2480,10 @@ fn parse_export(
|
|||||||
input: &mut TokenStream,
|
input: &mut TokenStream,
|
||||||
state: &mut ParseState,
|
state: &mut ParseState,
|
||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
mut settings: ParseSettings,
|
settings: ParseSettings,
|
||||||
) -> Result<Stmt, ParseError> {
|
) -> Result<Stmt, ParseError> {
|
||||||
|
let mut settings = settings;
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
@ -2518,8 +2554,10 @@ fn parse_block(
|
|||||||
input: &mut TokenStream,
|
input: &mut TokenStream,
|
||||||
state: &mut ParseState,
|
state: &mut ParseState,
|
||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
mut settings: ParseSettings,
|
settings: ParseSettings,
|
||||||
) -> Result<Stmt, ParseError> {
|
) -> Result<Stmt, ParseError> {
|
||||||
|
let mut settings = settings;
|
||||||
|
|
||||||
// Must start with {
|
// Must start with {
|
||||||
settings.pos = match input.next().expect(NEVER_ENDS) {
|
settings.pos = match input.next().expect(NEVER_ENDS) {
|
||||||
(Token::LeftBrace, pos) => pos,
|
(Token::LeftBrace, pos) => pos,
|
||||||
@ -2619,8 +2657,10 @@ fn parse_expr_stmt(
|
|||||||
input: &mut TokenStream,
|
input: &mut TokenStream,
|
||||||
state: &mut ParseState,
|
state: &mut ParseState,
|
||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
mut settings: ParseSettings,
|
settings: ParseSettings,
|
||||||
) -> Result<Stmt, ParseError> {
|
) -> Result<Stmt, ParseError> {
|
||||||
|
let mut settings = settings;
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
@ -2636,10 +2676,12 @@ fn parse_stmt(
|
|||||||
input: &mut TokenStream,
|
input: &mut TokenStream,
|
||||||
state: &mut ParseState,
|
state: &mut ParseState,
|
||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
mut settings: ParseSettings,
|
settings: ParseSettings,
|
||||||
) -> Result<Stmt, ParseError> {
|
) -> Result<Stmt, ParseError> {
|
||||||
use AccessMode::{ReadOnly, ReadWrite};
|
use AccessMode::{ReadOnly, ReadWrite};
|
||||||
|
|
||||||
|
let mut settings = settings;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
#[cfg(feature = "metadata")]
|
#[cfg(feature = "metadata")]
|
||||||
let comments = {
|
let comments = {
|
||||||
@ -2836,8 +2878,10 @@ fn parse_try_catch(
|
|||||||
input: &mut TokenStream,
|
input: &mut TokenStream,
|
||||||
state: &mut ParseState,
|
state: &mut ParseState,
|
||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
mut settings: ParseSettings,
|
settings: ParseSettings,
|
||||||
) -> Result<Stmt, ParseError> {
|
) -> Result<Stmt, ParseError> {
|
||||||
|
let mut settings = settings;
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
@ -2892,11 +2936,13 @@ fn parse_fn(
|
|||||||
state: &mut ParseState,
|
state: &mut ParseState,
|
||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
access: FnAccess,
|
access: FnAccess,
|
||||||
mut settings: ParseSettings,
|
settings: ParseSettings,
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
#[cfg(feature = "metadata")]
|
#[cfg(feature = "metadata")]
|
||||||
comments: StaticVec<String>,
|
comments: StaticVec<String>,
|
||||||
) -> Result<ScriptFnDef, ParseError> {
|
) -> Result<ScriptFnDef, ParseError> {
|
||||||
|
let mut settings = settings;
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
@ -3039,8 +3085,10 @@ fn parse_anon_fn(
|
|||||||
input: &mut TokenStream,
|
input: &mut TokenStream,
|
||||||
state: &mut ParseState,
|
state: &mut ParseState,
|
||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
mut settings: ParseSettings,
|
settings: ParseSettings,
|
||||||
) -> Result<(Expr, ScriptFnDef), ParseError> {
|
) -> Result<(Expr, ScriptFnDef), ParseError> {
|
||||||
|
let mut settings = settings;
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
|
16
src/scope.rs
16
src/scope.rs
@ -63,7 +63,7 @@ impl<'a> IntoIterator for Scope<'a> {
|
|||||||
type Item = (Cow<'a, str>, Dynamic);
|
type Item = (Cow<'a, str>, Dynamic);
|
||||||
type IntoIter = Box<dyn Iterator<Item = Self::Item> + 'a>;
|
type IntoIter = Box<dyn Iterator<Item = Self::Item> + 'a>;
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
fn into_iter(self) -> Self::IntoIter {
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
Box::new(
|
Box::new(
|
||||||
self.values
|
self.values
|
||||||
@ -293,7 +293,7 @@ impl<'a> Scope<'a> {
|
|||||||
/// assert!(my_scope.contains("x"));
|
/// assert!(my_scope.contains("x"));
|
||||||
/// assert!(!my_scope.contains("y"));
|
/// assert!(!my_scope.contains("y"));
|
||||||
/// ```
|
/// ```
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn contains(&self, name: &str) -> bool {
|
pub fn contains(&self, name: &str) -> bool {
|
||||||
self.names
|
self.names
|
||||||
@ -302,7 +302,7 @@ impl<'a> Scope<'a> {
|
|||||||
.any(|(key, _)| name == key.as_ref())
|
.any(|(key, _)| name == key.as_ref())
|
||||||
}
|
}
|
||||||
/// Find an entry in the [`Scope`], starting from the last.
|
/// Find an entry in the [`Scope`], starting from the last.
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) fn get_index(&self, name: &str) -> Option<(usize, AccessMode)> {
|
pub(crate) fn get_index(&self, name: &str) -> Option<(usize, AccessMode)> {
|
||||||
self.names
|
self.names
|
||||||
@ -329,7 +329,7 @@ impl<'a> Scope<'a> {
|
|||||||
/// my_scope.push("x", 42_i64);
|
/// my_scope.push("x", 42_i64);
|
||||||
/// assert_eq!(my_scope.get_value::<i64>("x").unwrap(), 42);
|
/// assert_eq!(my_scope.get_value::<i64>("x").unwrap(), 42);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_value<T: Variant + Clone>(&self, name: &str) -> Option<T> {
|
pub fn get_value<T: Variant + Clone>(&self, name: &str) -> Option<T> {
|
||||||
self.names
|
self.names
|
||||||
@ -398,7 +398,7 @@ impl<'a> Scope<'a> {
|
|||||||
///
|
///
|
||||||
/// assert_eq!(my_scope.get_value::<i64>("x").unwrap(), 123);
|
/// assert_eq!(my_scope.get_value::<i64>("x").unwrap(), 123);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_mut(&mut self, name: &str) -> Option<&mut Dynamic> {
|
pub fn get_mut(&mut self, name: &str) -> Option<&mut Dynamic> {
|
||||||
self.get_index(name)
|
self.get_index(name)
|
||||||
@ -444,7 +444,7 @@ impl<'a> Scope<'a> {
|
|||||||
}
|
}
|
||||||
/// Clone the [`Scope`], keeping only the last instances of each variable name.
|
/// Clone the [`Scope`], keeping only the last instances of each variable name.
|
||||||
/// Shadowed variables are omitted in the copy.
|
/// Shadowed variables are omitted in the copy.
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) fn clone_visible(&self) -> Self {
|
pub(crate) fn clone_visible(&self) -> Self {
|
||||||
let mut entries = Self::new();
|
let mut entries = Self::new();
|
||||||
@ -463,7 +463,7 @@ impl<'a> Scope<'a> {
|
|||||||
entries
|
entries
|
||||||
}
|
}
|
||||||
/// Get an iterator to entries in the [`Scope`].
|
/// Get an iterator to entries in the [`Scope`].
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) fn into_iter(
|
pub(crate) fn into_iter(
|
||||||
self,
|
self,
|
||||||
@ -507,7 +507,7 @@ impl<'a> Scope<'a> {
|
|||||||
}
|
}
|
||||||
/// Get an iterator to entries in the [`Scope`].
|
/// Get an iterator to entries in the [`Scope`].
|
||||||
/// Shared values are not expanded.
|
/// Shared values are not expanded.
|
||||||
#[inline(always)]
|
#[inline]
|
||||||
pub fn iter_raw(&self) -> impl Iterator<Item = (&str, bool, &Dynamic)> {
|
pub fn iter_raw(&self) -> impl Iterator<Item = (&str, bool, &Dynamic)> {
|
||||||
self.names
|
self.names
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -1266,11 +1266,12 @@ fn eat_next(stream: &mut impl InputStream, pos: &mut Position) -> Option<char> {
|
|||||||
/// Scan for a block comment until the end.
|
/// Scan for a block comment until the end.
|
||||||
fn scan_block_comment(
|
fn scan_block_comment(
|
||||||
stream: &mut impl InputStream,
|
stream: &mut impl InputStream,
|
||||||
mut level: usize,
|
level: usize,
|
||||||
pos: &mut Position,
|
pos: &mut Position,
|
||||||
mut comment: Option<&mut String>,
|
comment: Option<&mut String>,
|
||||||
) -> usize {
|
) -> usize {
|
||||||
let comment = &mut comment;
|
let mut level = level;
|
||||||
|
let mut comment = comment;
|
||||||
|
|
||||||
while let Some(c) = stream.get_next() {
|
while let Some(c) = stream.get_next() {
|
||||||
pos.advance();
|
pos.advance();
|
||||||
|
@ -168,6 +168,9 @@ fn test_array_with_structs() -> Result<(), Box<EvalAltResult>> {
|
|||||||
fn test_arrays_map_reduce() -> Result<(), Box<EvalAltResult>> {
|
fn test_arrays_map_reduce() -> Result<(), Box<EvalAltResult>> {
|
||||||
let engine = Engine::new();
|
let engine = Engine::new();
|
||||||
|
|
||||||
|
assert_eq!(engine.eval::<INT>("[1].map(|x| x + 41)[0]")?, 42);
|
||||||
|
assert_eq!(engine.eval::<INT>("([1].map(|x| x + 41))[0]")?, 42);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
convert_to_vec::<INT>(engine.eval(
|
convert_to_vec::<INT>(engine.eval(
|
||||||
"
|
"
|
||||||
|
@ -25,8 +25,8 @@ fn test_custom_syntax() -> Result<(), Box<EvalAltResult>> {
|
|||||||
|context, inputs| {
|
|context, inputs| {
|
||||||
let var_name = inputs[0].get_variable_name().unwrap().to_string();
|
let var_name = inputs[0].get_variable_name().unwrap().to_string();
|
||||||
let max = inputs[1].get_literal_value::<INT>().unwrap();
|
let max = inputs[1].get_literal_value::<INT>().unwrap();
|
||||||
let stmt = inputs.get(2).unwrap();
|
let stmt = &inputs[2];
|
||||||
let condition = inputs.get(3).unwrap();
|
let condition = &inputs[3];
|
||||||
|
|
||||||
context.scope_mut().push(var_name.clone(), 0 as INT);
|
context.scope_mut().push(var_name.clone(), 0 as INT);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user