commit
ccd498700d
@ -13,6 +13,7 @@ Bug fixes
|
|||||||
* Fixes concatenation of BLOB's and strings, where the BLOB's should be interpreted as UTF-8 encoded strings.
|
* Fixes concatenation of BLOB's and strings, where the BLOB's should be interpreted as UTF-8 encoded strings.
|
||||||
* Capturing an unknown variable in a closure no longer panics.
|
* Capturing an unknown variable in a closure no longer panics.
|
||||||
* Fixes panic in interpolated strings with constant expressions.
|
* Fixes panic in interpolated strings with constant expressions.
|
||||||
|
* Using `call_fn_raw` on a function without evaluating the AST no longer panics on namespace-qualified function calls due to `import` statements not run.
|
||||||
|
|
||||||
New features
|
New features
|
||||||
------------
|
------------
|
||||||
@ -38,6 +39,10 @@ New features
|
|||||||
|
|
||||||
* Crate-level functions `rhai::eval`, `rhai::run`, `rhai::eval_file`, `rhai::run_file` are added as convenient wrappers.
|
* Crate-level functions `rhai::eval`, `rhai::run`, `rhai::eval_file`, `rhai::run_file` are added as convenient wrappers.
|
||||||
|
|
||||||
|
### CustomType trait and TypeBuilder
|
||||||
|
|
||||||
|
* A new volatile API, `Engine::build_type`, enables registration of the entire API of a custom type in one go, provided that the custom type implements the `CustomType` trait (which uses `TypeBuilder` to register the API functions).
|
||||||
|
|
||||||
Enhancements
|
Enhancements
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ categories = ["no-std", "embedded", "wasm", "parser-implementations"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
smallvec = { version = "1.7", default-features = false, features = ["union", "const_new" ] }
|
smallvec = { version = "1.7", default-features = false, features = ["union", "const_new" ] }
|
||||||
ahash = { version = "0.7", default-features = false }
|
ahash = { version = "0.8", default-features = false }
|
||||||
num-traits = { version = "0.2", default-features = false }
|
num-traits = { version = "0.2", default-features = false }
|
||||||
bitflags = { version = "1", default-features = false }
|
bitflags = { version = "1", default-features = false }
|
||||||
smartstring = { version = "1", default-features = false }
|
smartstring = { version = "1", default-features = false }
|
||||||
@ -39,7 +39,8 @@ serde_bytes = "0.11"
|
|||||||
serde_json = { version = "1.0", default-features = false, features = ["alloc"] }
|
serde_json = { version = "1.0", default-features = false, features = ["alloc"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = ["std"]
|
||||||
|
std = ["ahash/std", "ahash/runtime-rng", "num-traits/std", "smartstring/std"]
|
||||||
unchecked = [] # unchecked arithmetic
|
unchecked = [] # unchecked arithmetic
|
||||||
sync = [] # restrict to only types that implement Send + Sync
|
sync = [] # restrict to only types that implement Send + Sync
|
||||||
no_position = [] # do not track position in the parser
|
no_position = [] # do not track position in the parser
|
||||||
|
1
doc/rhai-1.8.0-sync.json
Normal file
1
doc/rhai-1.8.0-sync.json
Normal file
File diff suppressed because one or more lines are too long
1
doc/rhai-1.8.0.json
Normal file
1
doc/rhai-1.8.0.json
Normal file
File diff suppressed because one or more lines are too long
@ -32,6 +32,15 @@ fn main() -> Result<(), Box<EvalAltResult>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl IntoIterator for TestStruct {
|
||||||
|
type Item = i64;
|
||||||
|
type IntoIter = std::vec::IntoIter<Self::Item>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
vec![self.x - 1, self.x, self.x + 1].into_iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl CustomType for TestStruct {
|
impl CustomType for TestStruct {
|
||||||
fn build(mut builder: TypeBuilder<Self>) {
|
fn build(mut builder: TypeBuilder<Self>) {
|
||||||
#[allow(deprecated)] // The TypeBuilder api is volatile.
|
#[allow(deprecated)] // The TypeBuilder api is volatile.
|
||||||
@ -40,6 +49,7 @@ fn main() -> Result<(), Box<EvalAltResult>> {
|
|||||||
.with_fn("new_ts", Self::new)
|
.with_fn("new_ts", Self::new)
|
||||||
.with_fn("update", Self::update)
|
.with_fn("update", Self::update)
|
||||||
.with_fn("calc", Self::calculate)
|
.with_fn("calc", Self::calculate)
|
||||||
|
.is_iterable()
|
||||||
.with_get_set("x", Self::get_x, Self::set_x);
|
.with_get_set("x", Self::get_x, Self::set_x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -63,8 +73,16 @@ fn main() -> Result<(), Box<EvalAltResult>> {
|
|||||||
let result = engine.eval::<i64>(
|
let result = engine.eval::<i64>(
|
||||||
"
|
"
|
||||||
let x = new_ts();
|
let x = new_ts();
|
||||||
|
|
||||||
x.x = 42;
|
x.x = 42;
|
||||||
|
|
||||||
|
for n in x {
|
||||||
|
x.x += n;
|
||||||
|
print(`n = ${n}, total = ${x.x}`);
|
||||||
|
}
|
||||||
|
|
||||||
x.update();
|
x.update();
|
||||||
|
|
||||||
x.calc(x.x)
|
x.calc(x.x)
|
||||||
",
|
",
|
||||||
)?;
|
)?;
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
/// Initialize user-provided state (shadows system-provided state, if any).
|
/// Initialize user-provided state (shadows system-provided state, if any).
|
||||||
fn init() {
|
fn init() {
|
||||||
// Add 'bool_state' and 'obj_state' as new state variables
|
// Add 'bool_state' and 'value' as new state variables
|
||||||
let bool_state = false;
|
let bool_state = false;
|
||||||
let value = 0;
|
let value = 0;
|
||||||
|
|
||||||
|
@ -1,17 +1,18 @@
|
|||||||
//! Trait to build a custom type for use with [`Engine`].
|
//! Trait to build a custom type for use with [`Engine`].
|
||||||
#![allow(deprecated)]
|
#![allow(deprecated)]
|
||||||
|
|
||||||
use crate::{
|
use crate::{types::dynamic::Variant, Engine, Identifier, RegisterNativeFunction, RhaiResultOf};
|
||||||
func::SendSync, types::dynamic::Variant, Engine, Identifier, RegisterNativeFunction,
|
|
||||||
RhaiResultOf,
|
|
||||||
};
|
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
|
|
||||||
/// Trait to build a custom type for use with an [`Engine`]
|
/// Trait to build the API of a custom type for use with an [`Engine`]
|
||||||
/// (i.e. register the type and its getters, setters, methods, etc.).
|
/// (i.e. register the type and its getters, setters, methods, etc.).
|
||||||
///
|
///
|
||||||
|
/// # WARNING - Volatile Trait
|
||||||
|
///
|
||||||
|
/// This API is volatile and may change in the future.
|
||||||
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
@ -71,9 +72,13 @@ pub trait CustomType: Variant + Clone {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Engine {
|
impl Engine {
|
||||||
/// Build a custom type for use with the [`Engine`].
|
/// Build the API of a custom type for use with the [`Engine`].
|
||||||
///
|
///
|
||||||
/// The custom type must implement [`CustomType`].
|
/// The custom type must implement [`CustomType`].
|
||||||
|
///
|
||||||
|
/// # WARNING - Unstable API
|
||||||
|
///
|
||||||
|
/// This API is volatile and may change in the future.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn build_type<T: CustomType>(&mut self) -> &mut Self {
|
pub fn build_type<T: CustomType>(&mut self) -> &mut Self {
|
||||||
T::build(TypeBuilder::new(self));
|
T::build(TypeBuilder::new(self));
|
||||||
@ -81,15 +86,15 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builder to build a custom type for use with an [`Engine`].
|
/// Builder to build the API of a custom type for use with an [`Engine`].
|
||||||
///
|
///
|
||||||
/// The type is automatically registered when this builder is dropped.
|
/// The type is automatically registered when this builder is dropped.
|
||||||
///
|
///
|
||||||
/// ## Pretty name
|
/// ## Pretty-Print Name
|
||||||
///
|
///
|
||||||
/// By default the type is registered with [`Engine::register_type`] (i.e. without a pretty name).
|
/// By default the type is registered with [`Engine::register_type`] (i.e. without a pretty-print name).
|
||||||
///
|
///
|
||||||
/// To define a pretty name, call [`with_name`][`TypeBuilder::with_name`],
|
/// To define a pretty-print name, call [`with_name`][`TypeBuilder::with_name`],
|
||||||
/// to use [`Engine::register_type_with_name`] instead.
|
/// to use [`Engine::register_type_with_name`] instead.
|
||||||
#[deprecated = "This type is NOT deprecated, but it is considered volatile and may change in the future."]
|
#[deprecated = "This type is NOT deprecated, but it is considered volatile and may change in the future."]
|
||||||
pub struct TypeBuilder<'a, T: Variant + Clone> {
|
pub struct TypeBuilder<'a, T: Variant + Clone> {
|
||||||
@ -99,6 +104,7 @@ pub struct TypeBuilder<'a, T: Variant + Clone> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T: Variant + Clone> TypeBuilder<'a, T> {
|
impl<'a, T: Variant + Clone> TypeBuilder<'a, T> {
|
||||||
|
/// Create a [`TypeBuilder`] linked to a particular [`Engine`] instance.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn new(engine: &'a mut Engine) -> Self {
|
fn new(engine: &'a mut Engine) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -110,7 +116,7 @@ impl<'a, T: Variant + Clone> TypeBuilder<'a, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T: Variant + Clone> TypeBuilder<'a, T> {
|
impl<'a, T: Variant + Clone> TypeBuilder<'a, T> {
|
||||||
/// Sets a pretty-print name for the `type_of` function.
|
/// Set a pretty-print name for the `type_of` function.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn with_name(&mut self, name: &'static str) -> &mut Self {
|
pub fn with_name(&mut self, name: &'static str) -> &mut Self {
|
||||||
self.name = Some(name);
|
self.name = Some(name);
|
||||||
@ -140,6 +146,20 @@ impl<'a, T: Variant + Clone> TypeBuilder<'a, T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a, T> TypeBuilder<'a, T>
|
||||||
|
where
|
||||||
|
T: Variant + Clone + IntoIterator,
|
||||||
|
<T as IntoIterator>::Item: Variant + Clone,
|
||||||
|
{
|
||||||
|
/// Register a type iterator.
|
||||||
|
/// This is an advanced API.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn is_iterable(&mut self) -> &mut Self {
|
||||||
|
self.engine.register_iterator::<T>();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
impl<'a, T: Variant + Clone> TypeBuilder<'a, T> {
|
impl<'a, T: Variant + Clone> TypeBuilder<'a, T> {
|
||||||
/// Register a getter function.
|
/// Register a getter function.
|
||||||
@ -151,7 +171,7 @@ impl<'a, T: Variant + Clone> TypeBuilder<'a, T> {
|
|||||||
pub fn with_get<V: Variant + Clone>(
|
pub fn with_get<V: Variant + Clone>(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: impl AsRef<str>,
|
name: impl AsRef<str>,
|
||||||
get_fn: impl Fn(&mut T) -> V + SendSync + 'static,
|
get_fn: impl Fn(&mut T) -> V + crate::func::SendSync + 'static,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
self.engine.register_get(name, get_fn);
|
self.engine.register_get(name, get_fn);
|
||||||
self
|
self
|
||||||
@ -166,7 +186,7 @@ impl<'a, T: Variant + Clone> TypeBuilder<'a, T> {
|
|||||||
pub fn with_get_result<V: Variant + Clone>(
|
pub fn with_get_result<V: Variant + Clone>(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: impl AsRef<str>,
|
name: impl AsRef<str>,
|
||||||
get_fn: impl Fn(&mut T) -> RhaiResultOf<V> + SendSync + 'static,
|
get_fn: impl Fn(&mut T) -> RhaiResultOf<V> + crate::func::SendSync + 'static,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
self.engine.register_get_result(name, get_fn);
|
self.engine.register_get_result(name, get_fn);
|
||||||
self
|
self
|
||||||
@ -179,7 +199,7 @@ impl<'a, T: Variant + Clone> TypeBuilder<'a, T> {
|
|||||||
pub fn with_set<V: Variant + Clone>(
|
pub fn with_set<V: Variant + Clone>(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: impl AsRef<str>,
|
name: impl AsRef<str>,
|
||||||
set_fn: impl Fn(&mut T, V) + SendSync + 'static,
|
set_fn: impl Fn(&mut T, V) + crate::func::SendSync + 'static,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
self.engine.register_set(name, set_fn);
|
self.engine.register_set(name, set_fn);
|
||||||
self
|
self
|
||||||
@ -192,7 +212,7 @@ impl<'a, T: Variant + Clone> TypeBuilder<'a, T> {
|
|||||||
pub fn with_set_result<V: Variant + Clone>(
|
pub fn with_set_result<V: Variant + Clone>(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: impl AsRef<str>,
|
name: impl AsRef<str>,
|
||||||
set_fn: impl Fn(&mut T, V) -> RhaiResultOf<()> + SendSync + 'static,
|
set_fn: impl Fn(&mut T, V) -> RhaiResultOf<()> + crate::func::SendSync + 'static,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
self.engine.register_set_result(name, set_fn);
|
self.engine.register_set_result(name, set_fn);
|
||||||
self
|
self
|
||||||
@ -207,8 +227,8 @@ impl<'a, T: Variant + Clone> TypeBuilder<'a, T> {
|
|||||||
pub fn with_get_set<V: Variant + Clone>(
|
pub fn with_get_set<V: Variant + Clone>(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: impl AsRef<str>,
|
name: impl AsRef<str>,
|
||||||
get_fn: impl Fn(&mut T) -> V + SendSync + 'static,
|
get_fn: impl Fn(&mut T) -> V + crate::func::SendSync + 'static,
|
||||||
set_fn: impl Fn(&mut T, V) + SendSync + 'static,
|
set_fn: impl Fn(&mut T, V) + crate::func::SendSync + 'static,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
self.engine.register_get_set(name, get_fn, set_fn);
|
self.engine.register_get_set(name, get_fn, set_fn);
|
||||||
self
|
self
|
||||||
@ -225,7 +245,7 @@ impl<'a, T: Variant + Clone> TypeBuilder<'a, T> {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn with_indexer_get<X: Variant + Clone, V: Variant + Clone>(
|
pub fn with_indexer_get<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 + crate::func::SendSync + 'static,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
self.engine.register_indexer_get(get_fn);
|
self.engine.register_indexer_get(get_fn);
|
||||||
self
|
self
|
||||||
@ -239,7 +259,7 @@ impl<'a, T: Variant + Clone> TypeBuilder<'a, T> {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn with_indexer_get_result<X: Variant + Clone, V: Variant + Clone>(
|
pub fn with_indexer_get_result<X: Variant + Clone, V: Variant + Clone>(
|
||||||
&mut self,
|
&mut self,
|
||||||
get_fn: impl Fn(&mut T, X) -> RhaiResultOf<V> + SendSync + 'static,
|
get_fn: impl Fn(&mut T, X) -> RhaiResultOf<V> + crate::func::SendSync + 'static,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
self.engine.register_indexer_get_result(get_fn);
|
self.engine.register_indexer_get_result(get_fn);
|
||||||
self
|
self
|
||||||
@ -251,7 +271,7 @@ impl<'a, T: Variant + Clone> TypeBuilder<'a, T> {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn with_indexer_set<X: Variant + Clone, V: Variant + Clone>(
|
pub fn with_indexer_set<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) + crate::func::SendSync + 'static,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
self.engine.register_indexer_set(set_fn);
|
self.engine.register_indexer_set(set_fn);
|
||||||
self
|
self
|
||||||
@ -263,7 +283,7 @@ impl<'a, T: Variant + Clone> TypeBuilder<'a, T> {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn with_indexer_set_result<X: Variant + Clone, V: Variant + Clone>(
|
pub fn with_indexer_set_result<X: Variant + Clone, V: Variant + Clone>(
|
||||||
&mut self,
|
&mut self,
|
||||||
set_fn: impl Fn(&mut T, X, V) -> RhaiResultOf<()> + SendSync + 'static,
|
set_fn: impl Fn(&mut T, X, V) -> RhaiResultOf<()> + crate::func::SendSync + 'static,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
self.engine.register_indexer_set_result(set_fn);
|
self.engine.register_indexer_set_result(set_fn);
|
||||||
self
|
self
|
||||||
@ -275,8 +295,8 @@ impl<'a, T: Variant + Clone> TypeBuilder<'a, T> {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn with_indexer_get_set<X: Variant + Clone, V: Variant + Clone>(
|
pub fn with_indexer_get_set<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 + crate::func::SendSync + 'static,
|
||||||
set_fn: impl Fn(&mut T, X, V) + SendSync + 'static,
|
set_fn: impl Fn(&mut T, X, V) + crate::func::SendSync + 'static,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
self.engine.register_indexer_get_set(get_fn, set_fn);
|
self.engine.register_indexer_get_set(get_fn, set_fn);
|
||||||
self
|
self
|
||||||
|
@ -31,7 +31,7 @@ bitflags! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl LangOptions {
|
impl LangOptions {
|
||||||
/// Create a new [`Options`] with default values.
|
/// Create a new [`LangOptions`] with default values.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self::IF_EXPR | Self::SWITCH_EXPR | Self::STMT_EXPR | Self::LOOPING | Self::SHADOW | {
|
Self::IF_EXPR | Self::SWITCH_EXPR | Self::STMT_EXPR | Self::LOOPING | Self::SHADOW | {
|
||||||
|
@ -274,7 +274,7 @@ impl AST {
|
|||||||
pub fn shared_lib(&self) -> &crate::Shared<crate::Module> {
|
pub fn shared_lib(&self) -> &crate::Shared<crate::Module> {
|
||||||
&self.lib
|
&self.lib
|
||||||
}
|
}
|
||||||
/// Get the embedded [module resolver][`ModuleResolver`].
|
/// Get the embedded [module resolver][crate::ModuleResolver].
|
||||||
#[cfg(not(feature = "internals"))]
|
#[cfg(not(feature = "internals"))]
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
@ -297,7 +297,7 @@ impl AST {
|
|||||||
) -> Option<&crate::Shared<crate::module::resolvers::StaticModuleResolver>> {
|
) -> Option<&crate::Shared<crate::module::resolvers::StaticModuleResolver>> {
|
||||||
self.resolver.as_ref()
|
self.resolver.as_ref()
|
||||||
}
|
}
|
||||||
/// Set the embedded [module resolver][`ModuleResolver`].
|
/// Set the embedded [module resolver][crate::ModuleResolver].
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn set_resolver(
|
pub(crate) fn set_resolver(
|
||||||
|
@ -35,7 +35,7 @@ impl From<&Expr> for ChainType {
|
|||||||
|
|
||||||
impl Engine {
|
impl Engine {
|
||||||
/// Chain-evaluate a dot/index chain.
|
/// Chain-evaluate a dot/index chain.
|
||||||
/// [`Position`] in [`EvalAltResult`] may be [`NONE`][Position::NONE] and should be set afterwards.
|
/// [`Position`] in [`EvalAltResult`][crate::EvalAltResult] may be [`NONE`][Position::NONE] and should be set afterwards.
|
||||||
fn eval_dot_index_chain_helper(
|
fn eval_dot_index_chain_helper(
|
||||||
&self,
|
&self,
|
||||||
global: &mut GlobalRuntimeState,
|
global: &mut GlobalRuntimeState,
|
||||||
@ -641,9 +641,7 @@ impl Engine {
|
|||||||
.map_err(|err| err.fill_position(op_pos))
|
.map_err(|err| err.fill_position(op_pos))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate a chain of indexes and store the results in a [`StaticVec`].
|
/// Evaluate a chain of indexes and store the results in a [`FnArgsVec`].
|
||||||
/// [`StaticVec`] is used to avoid an allocation in the overwhelming cases of
|
|
||||||
/// just a few levels of indexing.
|
|
||||||
fn eval_dot_index_chain_arguments(
|
fn eval_dot_index_chain_arguments(
|
||||||
&self,
|
&self,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
@ -804,7 +802,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get the value at the indexed position of a base type.
|
/// Get the value at the indexed position of a base type.
|
||||||
/// [`Position`] in [`EvalAltResult`] may be [`NONE`][Position::NONE] and should be set afterwards.
|
/// [`Position`] in [`EvalAltResult`][crate::EvalAltResult] may be [`NONE`][Position::NONE] and should be set afterwards.
|
||||||
fn get_indexed_mut<'t>(
|
fn get_indexed_mut<'t>(
|
||||||
&self,
|
&self,
|
||||||
global: &mut GlobalRuntimeState,
|
global: &mut GlobalRuntimeState,
|
||||||
|
@ -732,7 +732,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate a list of statements with no `this` pointer.
|
/// Evaluate a list of statements with no `this` pointer.
|
||||||
/// This is commonly used to evaluate a list of statements in an [`AST`] or a script function body.
|
/// This is commonly used to evaluate a list of statements in an [`AST`][crate::AST] or a script function body.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn eval_global_statements(
|
pub(crate) fn eval_global_statements(
|
||||||
&self,
|
&self,
|
||||||
|
@ -1924,9 +1924,7 @@ impl Module {
|
|||||||
/// cross-call each other.
|
/// cross-call each other.
|
||||||
///
|
///
|
||||||
/// Functions in the global namespace, plus all functions defined in the [`Module`], are
|
/// Functions in the global namespace, plus all functions defined in the [`Module`], are
|
||||||
/// _merged_ into a _unified_ namespace before each call.
|
/// _merged_ into a _unified_ namespace. Therefore, all functions will be found.
|
||||||
///
|
|
||||||
/// Therefore, all functions will be found.
|
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
@ -1959,16 +1957,14 @@ impl Module {
|
|||||||
/// cross-call each other.
|
/// cross-call each other.
|
||||||
///
|
///
|
||||||
/// Functions in the global namespace, plus all functions defined in the [`Module`], are
|
/// Functions in the global namespace, plus all functions defined in the [`Module`], are
|
||||||
/// _merged_ into a _unified_ namespace before each call.
|
/// _merged_ into a _unified_ namespace. Therefore, all functions will be found.
|
||||||
///
|
|
||||||
/// Therefore, all functions will be found.
|
|
||||||
///
|
///
|
||||||
/// # WARNING - Low Level API
|
/// # WARNING - Low Level API
|
||||||
///
|
///
|
||||||
/// This function is very low level.
|
/// This function is very low level.
|
||||||
///
|
///
|
||||||
/// In particular, the [`global`][crate::eval::GlobalRuntimeState] parameter allows the
|
/// In particular, the [`global`][crate::GlobalRuntimeState] parameter allows the entire
|
||||||
/// entire calling environment to be encapsulated, including automatic global constants.
|
/// calling environment to be encapsulated, including automatic global constants.
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
pub fn eval_ast_as_new_raw(
|
pub fn eval_ast_as_new_raw(
|
||||||
engine: &crate::Engine,
|
engine: &crate::Engine,
|
||||||
|
104
src/parser.rs
104
src/parser.rs
@ -72,6 +72,9 @@ pub struct ParseState<'e> {
|
|||||||
/// Encapsulates a local stack with imported [module][crate::Module] names.
|
/// Encapsulates a local stack with imported [module][crate::Module] names.
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
pub imports: StaticVec<Identifier>,
|
pub imports: StaticVec<Identifier>,
|
||||||
|
/// List of globally-imported [module][crate::Module] names.
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
pub global_imports: StaticVec<Identifier>,
|
||||||
/// Maximum levels of expression nesting (0 for unlimited).
|
/// Maximum levels of expression nesting (0 for unlimited).
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
pub max_expr_depth: usize,
|
pub max_expr_depth: usize,
|
||||||
@ -91,7 +94,8 @@ impl fmt::Debug for ParseState<'_> {
|
|||||||
f.field("external_vars", &self.external_vars)
|
f.field("external_vars", &self.external_vars)
|
||||||
.field("allow_capture", &self.allow_capture);
|
.field("allow_capture", &self.allow_capture);
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
f.field("imports", &self.imports);
|
f.field("imports", &self.imports)
|
||||||
|
.field("global_imports", &self.global_imports);
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
f.field("max_expr_depth", &self.max_expr_depth);
|
f.field("max_expr_depth", &self.max_expr_depth);
|
||||||
f.finish()
|
f.finish()
|
||||||
@ -117,6 +121,8 @@ impl<'e> ParseState<'e> {
|
|||||||
block_stack_len: 0,
|
block_stack_len: 0,
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
imports: StaticVec::new_const(),
|
imports: StaticVec::new_const(),
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
global_imports: StaticVec::new_const(),
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
max_expr_depth: engine.max_expr_depth(),
|
max_expr_depth: engine.max_expr_depth(),
|
||||||
}
|
}
|
||||||
@ -159,13 +165,13 @@ impl<'e> ParseState<'e> {
|
|||||||
/// The return value is the offset to be deducted from `ParseState::stack::len()`,
|
/// The return value is the offset to be deducted from `ParseState::stack::len()`,
|
||||||
/// i.e. the top element of [`ParseState`]'s variables stack is offset 1.
|
/// i.e. the top element of [`ParseState`]'s variables stack is offset 1.
|
||||||
///
|
///
|
||||||
/// # Return value: `(index, is_func)`
|
/// # Return value: `(index, is_func_name)`
|
||||||
///
|
///
|
||||||
/// * `index`: `None` when the variable name is not found in the `stack`,
|
/// * `index`: `None` when the variable name is not found in the `stack`,
|
||||||
/// otherwise the index value.
|
/// otherwise the index value.
|
||||||
///
|
///
|
||||||
/// * `is_func`: `true` if the variable is actually the name of a function
|
/// * `is_func_name`: `true` if the variable is actually the name of a function
|
||||||
/// (in which case it will be converted into a function pointer).
|
/// (in which case it will be converted into a function pointer).
|
||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn access_var(
|
pub fn access_var(
|
||||||
@ -179,14 +185,15 @@ impl<'e> ParseState<'e> {
|
|||||||
let (index, hit_barrier) = self.find_var(name);
|
let (index, hit_barrier) = self.find_var(name);
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
let is_func = lib.values().any(|f| f.name == name);
|
let is_func_name = lib.values().any(|f| f.name == name);
|
||||||
|
|
||||||
#[cfg(feature = "no_function")]
|
#[cfg(feature = "no_function")]
|
||||||
let is_func = false;
|
let is_func_name = false;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
if self.allow_capture {
|
if self.allow_capture {
|
||||||
if !is_func && index == 0 && !self.external_vars.iter().any(|v| v.as_str() == name) {
|
if !is_func_name && index == 0 && !self.external_vars.iter().any(|v| v.as_str() == name)
|
||||||
|
{
|
||||||
self.external_vars.push(crate::ast::Ident {
|
self.external_vars.push(crate::ast::Ident {
|
||||||
name: name.into(),
|
name: name.into(),
|
||||||
pos: _pos,
|
pos: _pos,
|
||||||
@ -202,7 +209,7 @@ impl<'e> ParseState<'e> {
|
|||||||
NonZeroUsize::new(index)
|
NonZeroUsize::new(index)
|
||||||
};
|
};
|
||||||
|
|
||||||
(index, is_func)
|
(index, is_func_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Find a module by name in the [`ParseState`], searching in reverse.
|
/// Find a module by name in the [`ParseState`], searching in reverse.
|
||||||
@ -251,15 +258,15 @@ impl<'e> ParseState<'e> {
|
|||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||||
struct ParseSettings {
|
struct ParseSettings {
|
||||||
/// Is the construct being parsed located at global level?
|
/// Is the construct being parsed located at global level?
|
||||||
is_global: bool,
|
at_global_level: bool,
|
||||||
/// Is the construct being parsed located at function definition level?
|
/// Is the construct being parsed located inside a function definition?
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
is_function_scope: bool,
|
in_fn_scope: bool,
|
||||||
/// Is the construct being parsed located inside a closure?
|
/// Is the construct being parsed located inside a closure definition?
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
is_closure_scope: bool,
|
in_closure: bool,
|
||||||
/// Is the current position inside a loop?
|
/// Is the construct being parsed located inside a breakable loop?
|
||||||
is_breakable: bool,
|
is_breakable: bool,
|
||||||
/// Language options in effect (overrides Engine options).
|
/// Language options in effect (overrides Engine options).
|
||||||
options: LangOptions,
|
options: LangOptions,
|
||||||
@ -557,6 +564,7 @@ impl Engine {
|
|||||||
if settings.options.contains(LangOptions::STRICT_VAR)
|
if settings.options.contains(LangOptions::STRICT_VAR)
|
||||||
&& index.is_none()
|
&& index.is_none()
|
||||||
&& !is_global
|
&& !is_global
|
||||||
|
&& !state.global_imports.iter().any(|m| m == root)
|
||||||
&& !self.global_sub_modules.contains_key(root)
|
&& !self.global_sub_modules.contains_key(root)
|
||||||
{
|
{
|
||||||
return Err(
|
return Err(
|
||||||
@ -624,6 +632,7 @@ impl Engine {
|
|||||||
if settings.options.contains(LangOptions::STRICT_VAR)
|
if settings.options.contains(LangOptions::STRICT_VAR)
|
||||||
&& index.is_none()
|
&& index.is_none()
|
||||||
&& !is_global
|
&& !is_global
|
||||||
|
&& !state.global_imports.iter().any(|m| m == root)
|
||||||
&& !self.global_sub_modules.contains_key(root)
|
&& !self.global_sub_modules.contains_key(root)
|
||||||
{
|
{
|
||||||
return Err(PERR::ModuleUndefined(root.to_string())
|
return Err(PERR::ModuleUndefined(root.to_string())
|
||||||
@ -1351,7 +1360,17 @@ impl Engine {
|
|||||||
ParseState::new(self, state.scope, state.tokenizer_control.clone());
|
ParseState::new(self, state.scope, state.tokenizer_control.clone());
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
new_state.imports.clone_from(&state.imports);
|
{
|
||||||
|
// Do not allow storing an index to a globally-imported module
|
||||||
|
// just in case the function is separated from this `AST`.
|
||||||
|
//
|
||||||
|
// Keep them in `global_imports` instead so that strict variables
|
||||||
|
// mode will not complain.
|
||||||
|
new_state.global_imports.clone_from(&state.global_imports);
|
||||||
|
new_state
|
||||||
|
.global_imports
|
||||||
|
.extend(state.imports.iter().cloned());
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
{
|
{
|
||||||
@ -1370,10 +1389,10 @@ impl Engine {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let new_settings = ParseSettings {
|
let new_settings = ParseSettings {
|
||||||
is_global: false,
|
at_global_level: false,
|
||||||
is_function_scope: true,
|
in_fn_scope: true,
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
is_closure_scope: true,
|
in_closure: true,
|
||||||
is_breakable: false,
|
is_breakable: false,
|
||||||
level: 0,
|
level: 0,
|
||||||
options,
|
options,
|
||||||
@ -1388,7 +1407,7 @@ impl Engine {
|
|||||||
let (index, is_func) = state.access_var(name, lib, *pos);
|
let (index, is_func) = state.access_var(name, lib, *pos);
|
||||||
|
|
||||||
if settings.options.contains(LangOptions::STRICT_VAR)
|
if settings.options.contains(LangOptions::STRICT_VAR)
|
||||||
&& !settings.is_closure_scope
|
&& !settings.in_closure
|
||||||
&& index.is_none()
|
&& index.is_none()
|
||||||
&& !state.scope.contains(name)
|
&& !state.scope.contains(name)
|
||||||
&& !is_func
|
&& !is_func
|
||||||
@ -1583,7 +1602,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
// Access to `this` as a variable is OK within a function scope
|
// Access to `this` as a variable is OK within a function scope
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
_ if &*s == KEYWORD_THIS && settings.is_function_scope => Expr::Variable(
|
_ if &*s == KEYWORD_THIS && settings.in_fn_scope => Expr::Variable(
|
||||||
(None, ns, 0, state.get_identifier("", s)).into(),
|
(None, ns, 0, state.get_identifier("", s)).into(),
|
||||||
None,
|
None,
|
||||||
settings.pos,
|
settings.pos,
|
||||||
@ -1789,6 +1808,7 @@ impl Engine {
|
|||||||
if settings.options.contains(LangOptions::STRICT_VAR)
|
if settings.options.contains(LangOptions::STRICT_VAR)
|
||||||
&& index.is_none()
|
&& index.is_none()
|
||||||
&& !is_global
|
&& !is_global
|
||||||
|
&& !state.global_imports.iter().any(|m| m == root)
|
||||||
&& !self.global_sub_modules.contains_key(root)
|
&& !self.global_sub_modules.contains_key(root)
|
||||||
{
|
{
|
||||||
return Err(
|
return Err(
|
||||||
@ -3049,7 +3069,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Parse statements inside the block
|
// Parse statements inside the block
|
||||||
settings.is_global = false;
|
settings.at_global_level = false;
|
||||||
|
|
||||||
let stmt = self.parse_stmt(input, state, lib, settings.level_up())?;
|
let stmt = self.parse_stmt(input, state, lib, settings.level_up())?;
|
||||||
|
|
||||||
@ -3145,7 +3165,7 @@ impl Engine {
|
|||||||
unreachable!("doc-comment expected but gets {:?}", comment);
|
unreachable!("doc-comment expected but gets {:?}", comment);
|
||||||
}
|
}
|
||||||
|
|
||||||
if !settings.is_global {
|
if !settings.at_global_level {
|
||||||
return Err(PERR::WrongDocComment.into_err(comments_pos));
|
return Err(PERR::WrongDocComment.into_err(comments_pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3187,7 +3207,9 @@ impl Engine {
|
|||||||
|
|
||||||
// fn ...
|
// fn ...
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
Token::Fn if !settings.is_global => Err(PERR::WrongFnDefinition.into_err(token_pos)),
|
Token::Fn if !settings.at_global_level => {
|
||||||
|
Err(PERR::WrongFnDefinition.into_err(token_pos))
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
Token::Fn | Token::Private => {
|
Token::Fn | Token::Private => {
|
||||||
@ -3204,7 +3226,17 @@ impl Engine {
|
|||||||
ParseState::new(self, state.scope, state.tokenizer_control.clone());
|
ParseState::new(self, state.scope, state.tokenizer_control.clone());
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
new_state.imports.clone_from(&state.imports);
|
{
|
||||||
|
// Do not allow storing an index to a globally-imported module
|
||||||
|
// just in case the function is separated from this `AST`.
|
||||||
|
//
|
||||||
|
// Keep them in `global_imports` instead so that strict variables
|
||||||
|
// mode will not complain.
|
||||||
|
new_state.global_imports.clone_from(&state.global_imports);
|
||||||
|
new_state
|
||||||
|
.global_imports
|
||||||
|
.extend(state.imports.iter().cloned());
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
{
|
{
|
||||||
@ -3218,10 +3250,10 @@ impl Engine {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let new_settings = ParseSettings {
|
let new_settings = ParseSettings {
|
||||||
is_global: false,
|
at_global_level: false,
|
||||||
is_function_scope: true,
|
in_fn_scope: true,
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
is_closure_scope: false,
|
in_closure: false,
|
||||||
is_breakable: false,
|
is_breakable: false,
|
||||||
level: 0,
|
level: 0,
|
||||||
options,
|
options,
|
||||||
@ -3306,7 +3338,7 @@ impl Engine {
|
|||||||
// `return`/`throw` at <EOF>
|
// `return`/`throw` at <EOF>
|
||||||
(Token::EOF, ..) => Ok(Stmt::Return(None, return_type, token_pos)),
|
(Token::EOF, ..) => Ok(Stmt::Return(None, return_type, token_pos)),
|
||||||
// `return`/`throw` at end of block
|
// `return`/`throw` at end of block
|
||||||
(Token::RightBrace, ..) if !settings.is_global => {
|
(Token::RightBrace, ..) if !settings.at_global_level => {
|
||||||
Ok(Stmt::Return(None, return_type, token_pos))
|
Ok(Stmt::Return(None, return_type, token_pos))
|
||||||
}
|
}
|
||||||
// `return;` or `throw;`
|
// `return;` or `throw;`
|
||||||
@ -3328,7 +3360,9 @@ impl Engine {
|
|||||||
Token::Import => self.parse_import(input, state, lib, settings.level_up()),
|
Token::Import => self.parse_import(input, state, lib, settings.level_up()),
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
Token::Export if !settings.is_global => Err(PERR::WrongExport.into_err(token_pos)),
|
Token::Export if !settings.at_global_level => {
|
||||||
|
Err(PERR::WrongExport.into_err(token_pos))
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
Token::Export => self.parse_export(input, state, lib, settings.level_up()),
|
Token::Export => self.parse_export(input, state, lib, settings.level_up()),
|
||||||
@ -3688,12 +3722,12 @@ impl Engine {
|
|||||||
options.remove(LangOptions::ANON_FN);
|
options.remove(LangOptions::ANON_FN);
|
||||||
|
|
||||||
let settings = ParseSettings {
|
let settings = ParseSettings {
|
||||||
is_global: true,
|
at_global_level: true,
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
is_function_scope: false,
|
in_fn_scope: false,
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
is_closure_scope: false,
|
in_closure: false,
|
||||||
is_breakable: false,
|
is_breakable: false,
|
||||||
level: 0,
|
level: 0,
|
||||||
options,
|
options,
|
||||||
@ -3743,12 +3777,12 @@ impl Engine {
|
|||||||
|
|
||||||
while !input.peek().expect(NEVER_ENDS).0.is_eof() {
|
while !input.peek().expect(NEVER_ENDS).0.is_eof() {
|
||||||
let settings = ParseSettings {
|
let settings = ParseSettings {
|
||||||
is_global: true,
|
at_global_level: true,
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
is_function_scope: false,
|
in_fn_scope: false,
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
is_closure_scope: false,
|
in_closure: false,
|
||||||
is_breakable: false,
|
is_breakable: false,
|
||||||
options: self.options,
|
options: self.options,
|
||||||
level: 0,
|
level: 0,
|
||||||
|
@ -29,7 +29,7 @@ mod private {
|
|||||||
use crate::func::SendSync;
|
use crate::func::SendSync;
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
|
|
||||||
/// A sealed trait that prevents other crates from implementing [`Variant`].
|
/// A sealed trait that prevents other crates from implementing [`Variant`][super::Variant].
|
||||||
pub trait Sealed {}
|
pub trait Sealed {}
|
||||||
|
|
||||||
impl<T: Any + Clone + SendSync> Sealed for T {}
|
impl<T: Any + Clone + SendSync> Sealed for T {}
|
||||||
|
@ -527,7 +527,7 @@ impl EvalAltResult {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
/// 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(never)]
|
#[inline(never)]
|
||||||
#[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> {
|
||||||
|
@ -45,11 +45,22 @@ fn build_type() -> Result<(), Box<EvalAltResult>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl IntoIterator for Vec3 {
|
||||||
|
type Item = INT;
|
||||||
|
type IntoIter = std::vec::IntoIter<Self::Item>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
vec![self.x, self.y, self.z].into_iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl CustomType for Vec3 {
|
impl CustomType for Vec3 {
|
||||||
fn build(mut builder: TypeBuilder<Self>) {
|
fn build(mut builder: TypeBuilder<Self>) {
|
||||||
builder
|
builder
|
||||||
.with_name("Vec3")
|
.with_name("Vec3")
|
||||||
|
.is_iterable()
|
||||||
.with_fn("vec3", Self::new)
|
.with_fn("vec3", Self::new)
|
||||||
|
.is_iterable()
|
||||||
.with_get_set("x", Self::get_x, Self::set_x)
|
.with_get_set("x", Self::get_x, Self::set_x)
|
||||||
.with_get_set("y", Self::get_y, Self::set_y)
|
.with_get_set("y", Self::get_y, Self::set_y)
|
||||||
.with_get_set("z", Self::get_z, Self::set_z);
|
.with_get_set("z", Self::get_z, Self::set_z);
|
||||||
@ -117,6 +128,19 @@ fn build_type() -> Result<(), Box<EvalAltResult>> {
|
|||||||
)?,
|
)?,
|
||||||
Vec3::new(5, 6, 7),
|
Vec3::new(5, 6, 7),
|
||||||
);
|
);
|
||||||
|
assert_eq!(
|
||||||
|
engine.eval::<INT>(
|
||||||
|
"
|
||||||
|
let sum = 0;
|
||||||
|
let v = vec3(1, 2, 3);
|
||||||
|
for i in v {
|
||||||
|
sum += i;
|
||||||
|
}
|
||||||
|
sum
|
||||||
|
",
|
||||||
|
)?,
|
||||||
|
6,
|
||||||
|
);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user