From b789c319e71fab539dff80575563f3f855bd7c50 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Fri, 19 Feb 2021 15:17:14 +0800 Subject: [PATCH 1/6] Rename serde_impl to serde. --- src/lib.rs | 9 +-------- src/{serde_impl => serde}/de.rs | 2 +- src/{serde_impl => serde}/deserialize.rs | 0 src/{serde_impl => serde}/metadata.rs | 0 src/serde/mod.rs | 14 ++++++++++++++ src/{serde_impl => serde}/ser.rs | 6 +++--- src/{serde_impl => serde}/serialize.rs | 0 src/{serde_impl => serde}/str.rs | 0 src/serde_impl/mod.rs | 10 ---------- 9 files changed, 19 insertions(+), 22 deletions(-) rename src/{serde_impl => serde}/de.rs (99%) rename src/{serde_impl => serde}/deserialize.rs (100%) rename src/{serde_impl => serde}/metadata.rs (100%) create mode 100644 src/serde/mod.rs rename src/{serde_impl => serde}/ser.rs (99%) rename src/{serde_impl => serde}/serialize.rs (100%) rename src/{serde_impl => serde}/str.rs (100%) delete mode 100644 src/serde_impl/mod.rs diff --git a/src/lib.rs b/src/lib.rs index 401cc576..04f494c6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -79,8 +79,6 @@ mod parser; pub mod plugin; mod result; mod scope; -#[cfg(feature = "serde")] -mod serde_impl; mod stdlib; mod syntax; mod token; @@ -168,13 +166,8 @@ pub use module::ModuleResolver; #[cfg(not(feature = "no_module"))] pub use module::resolvers as module_resolvers; -/// _(SERDE)_ Serialization and deserialization support for [`serde`](https://crates.io/crates/serde). -/// Exported under the `serde` feature. #[cfg(feature = "serde")] -pub mod serde { - pub use super::serde_impl::de::from_dynamic; - pub use super::serde_impl::ser::to_dynamic; -} +pub mod serde; #[cfg(not(feature = "no_optimize"))] pub use optimize::OptimizationLevel; diff --git a/src/serde_impl/de.rs b/src/serde/de.rs similarity index 99% rename from src/serde_impl/de.rs rename to src/serde/de.rs index f852fb89..80ba7555 100644 --- a/src/serde_impl/de.rs +++ b/src/serde/de.rs @@ -17,7 +17,7 @@ use crate::Map; /// /// The reference is necessary because the deserialized type may hold references /// (especially `&str`) to the source [`Dynamic`][crate::Dynamic]. -pub struct DynamicDeserializer<'a> { +struct DynamicDeserializer<'a> { value: &'a Dynamic, } diff --git a/src/serde_impl/deserialize.rs b/src/serde/deserialize.rs similarity index 100% rename from src/serde_impl/deserialize.rs rename to src/serde/deserialize.rs diff --git a/src/serde_impl/metadata.rs b/src/serde/metadata.rs similarity index 100% rename from src/serde_impl/metadata.rs rename to src/serde/metadata.rs diff --git a/src/serde/mod.rs b/src/serde/mod.rs new file mode 100644 index 00000000..a3819556 --- /dev/null +++ b/src/serde/mod.rs @@ -0,0 +1,14 @@ +//! _(SERDE)_ Serialization and deserialization support for [`serde`](https://crates.io/crates/serde). +//! Exported under the `serde` feature only. + +mod de; +mod deserialize; +mod ser; +mod serialize; +mod str; + +#[cfg(feature = "metadata")] +mod metadata; + +pub use de::from_dynamic; +pub use ser::to_dynamic; diff --git a/src/serde_impl/ser.rs b/src/serde/ser.rs similarity index 99% rename from src/serde_impl/ser.rs rename to src/serde/ser.rs index 167a59ef..a833c3b4 100644 --- a/src/serde_impl/ser.rs +++ b/src/serde/ser.rs @@ -14,7 +14,7 @@ use crate::Array; use crate::Map; /// Serializer for [`Dynamic`][crate::Dynamic] which is kept as a reference. -pub struct DynamicSerializer { +struct DynamicSerializer { /// Buffer to hold a temporary key. _key: Dynamic, /// Buffer to hold a temporary value. @@ -639,7 +639,7 @@ impl SerializeStruct for DynamicSerializer { } #[cfg(not(any(feature = "no_object", feature = "no_index")))] -pub struct TupleVariantSerializer { +struct TupleVariantSerializer { variant: &'static str, array: Array, } @@ -664,7 +664,7 @@ impl serde::ser::SerializeTupleVariant for TupleVariantSerializer { } #[cfg(not(feature = "no_object"))] -pub struct StructVariantSerializer { +struct StructVariantSerializer { variant: &'static str, map: Map, } diff --git a/src/serde_impl/serialize.rs b/src/serde/serialize.rs similarity index 100% rename from src/serde_impl/serialize.rs rename to src/serde/serialize.rs diff --git a/src/serde_impl/str.rs b/src/serde/str.rs similarity index 100% rename from src/serde_impl/str.rs rename to src/serde/str.rs diff --git a/src/serde_impl/mod.rs b/src/serde_impl/mod.rs deleted file mode 100644 index 1c90abbf..00000000 --- a/src/serde_impl/mod.rs +++ /dev/null @@ -1,10 +0,0 @@ -//! Helper module defining serialization/deserialization support for [`serde`]. - -pub mod de; -mod deserialize; -pub mod ser; -mod serialize; -mod str; - -#[cfg(feature = "metadata")] -pub mod metadata; From 4e3ab7fa6a11e481198aee57cdd907b258c80e64 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Fri, 19 Feb 2021 15:49:51 +0800 Subject: [PATCH 2/6] Add compiler guards for mutually-exclusive features. --- src/lib.rs | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 04f494c6..db6e4687 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -41,7 +41,7 @@ //! engine.register_fn("compute", compute_something); //! //! # #[cfg(not(feature = "no_std"))] -//! # #[cfg(not(target_arch = "wasm32"))] +//! # #[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))] //! assert_eq!( //! // Evaluate the script, expects a 'bool' return //! engine.eval_file::("my_script.rhai".into())?, @@ -61,6 +61,8 @@ #[cfg(feature = "no_std")] extern crate alloc; +// Internal modules + mod ast; mod dynamic; mod engine; @@ -207,3 +209,29 @@ type StaticVec = smallvec::SmallVec<[T; 4]>; /// Exported under the `internals` feature only. #[cfg(feature = "internals")] pub type StaticVec = smallvec::SmallVec<[T; 4]>; + +// Compiler guards against mutually-exclusive feature flags + +#[cfg(feature = "no_float")] +#[cfg(feature = "f32_float")] +compile_error!("'f32_float' cannot be used with 'no_float'"); + +#[cfg(feature = "no_std")] +#[cfg(feature = "wasm-bindgen")] +compile_error!("'wasm-bindgen' cannot be used with 'no-std'"); + +#[cfg(feature = "no_std")] +#[cfg(feature = "stdweb")] +compile_error!("'stdweb' cannot be used with 'no-std'"); + +#[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] +#[cfg(feature = "no_std")] +compile_error!("'no_std' cannot be used for WASM target"); + +#[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))] +#[cfg(feature = "wasm-bindgen")] +compile_error!("'wasm-bindgen' should not be used non-WASM target"); + +#[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))] +#[cfg(feature = "stdweb")] +compile_error!("'stdweb' should not be used non-WASM target"); From 724ad0591634cfae375ec0f7857d54668bdbfec5 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Fri, 19 Feb 2021 15:50:48 +0800 Subject: [PATCH 3/6] Add wasm64 as potential target. --- Cargo.toml | 5 ++++- src/dynamic.rs | 6 +++--- src/engine.rs | 6 +++--- src/engine_api.rs | 14 +++++++------- src/module/resolvers/mod.rs | 4 ++-- src/packages/arithmetic.rs | 6 +++--- src/packages/array_basic.rs | 4 ++-- src/packages/logic.rs | 4 ++-- src/packages/math_basic.rs | 8 ++++---- src/packages/string_basic.rs | 6 +++--- src/packages/string_more.rs | 4 ++-- src/packages/time_basic.rs | 26 +++++++++++--------------- src/stdlib.rs | 2 +- 13 files changed, 47 insertions(+), 48 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0911adfb..c1bff9aa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,7 +44,7 @@ no_function = [ "no_closure" ] # no script-defined functions (meaning no closur no_closure = [] # no automatic sharing and capture of anonymous functions to external variables no_module = [] # no modules internals = [] # expose internal data structures -unicode-xid-ident = ["unicode-xid"] # allow Unicode Standard Annex #31 for identifiers. +unicode-xid-ident = [ "unicode-xid" ] # allow Unicode Standard Annex #31 for identifiers. metadata = [ "serde", "serde_json" ] # enables exporting functions metadata to JSON # compiling for no-std @@ -107,5 +107,8 @@ optional = true [target.'cfg(target_arch = "wasm32")'.dependencies] instant= { version = "0.1" } # WASM implementation of std::time::Instant +[target.'cfg(target_arch = "wasm64")'.dependencies] +instant= { version = "0.1" } # WASM implementation of std::time::Instant + [package.metadata.docs.rs] features = [ "metadata", "internals" ] diff --git a/src/dynamic.rs b/src/dynamic.rs index afd1e099..a220f86f 100644 --- a/src/dynamic.rs +++ b/src/dynamic.rs @@ -25,12 +25,12 @@ use crate::Array; use crate::Map; #[cfg(not(feature = "no_std"))] -#[cfg(not(target_arch = "wasm32"))] +#[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))] use crate::stdlib::time::Instant; use fmt::Debug; #[cfg(not(feature = "no_std"))] -#[cfg(target_arch = "wasm32")] +#[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] use instant::Instant; mod private { @@ -807,7 +807,7 @@ impl Dynamic { /// [`Arc`][std::sync::Arc]`<`[`RwLock`][std::sync::RwLock]`<`[`Dynamic`]`>>` /// depending on the `sync` feature. /// - /// Not available under [`no_closure`]. + /// Not available under `no_closure`. /// /// Shared [`Dynamic`] values are relatively cheap to clone as they simply increment the /// reference counts. diff --git a/src/engine.rs b/src/engine.rs index 0b164d91..b5586849 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -807,7 +807,7 @@ pub fn is_anonymous_fn(fn_name: &str) -> bool { #[inline(always)] fn default_print(_s: &str) { #[cfg(not(feature = "no_std"))] - #[cfg(not(target_arch = "wasm32"))] + #[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))] println!("{}", _s); } @@ -815,7 +815,7 @@ fn default_print(_s: &str) { #[inline(always)] fn default_debug(_s: &str, _source: Option<&str>, _pos: Position) { #[cfg(not(feature = "no_std"))] - #[cfg(not(target_arch = "wasm32"))] + #[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))] if let Some(source) = _source { println!("{} @ {:?} | {}", source, _pos, _s); } else { @@ -863,7 +863,7 @@ impl Engine { #[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_std"))] - #[cfg(not(target_arch = "wasm32"))] + #[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))] module_resolver: Box::new(crate::module::resolvers::FileModuleResolver::new()), #[cfg(not(feature = "no_module"))] #[cfg(any(feature = "no_std", target_arch = "wasm32",))] diff --git a/src/engine_api.rs b/src/engine_api.rs index f45403a3..808a2eff 100644 --- a/src/engine_api.rs +++ b/src/engine_api.rs @@ -1028,7 +1028,7 @@ impl Engine { } /// Read the contents of a file into a string. #[cfg(not(feature = "no_std"))] - #[cfg(not(target_arch = "wasm32"))] + #[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))] #[inline] fn read_file(path: crate::stdlib::path::PathBuf) -> Result> { use crate::stdlib::io::Read; @@ -1074,7 +1074,7 @@ impl Engine { /// # } /// ``` #[cfg(not(feature = "no_std"))] - #[cfg(not(target_arch = "wasm32"))] + #[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))] #[inline(always)] pub fn compile_file( &self, @@ -1116,7 +1116,7 @@ impl Engine { /// # } /// ``` #[cfg(not(feature = "no_std"))] - #[cfg(not(target_arch = "wasm32"))] + #[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))] #[inline(always)] pub fn compile_file_with_scope( &self, @@ -1301,7 +1301,7 @@ impl Engine { /// # } /// ``` #[cfg(not(feature = "no_std"))] - #[cfg(not(target_arch = "wasm32"))] + #[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))] #[inline(always)] pub fn eval_file( &self, @@ -1331,7 +1331,7 @@ impl Engine { /// # } /// ``` #[cfg(not(feature = "no_std"))] - #[cfg(not(target_arch = "wasm32"))] + #[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))] #[inline(always)] pub fn eval_file_with_scope( &self, @@ -1543,7 +1543,7 @@ impl Engine { /// /// Not available under `no_std` or `WASM`. #[cfg(not(feature = "no_std"))] - #[cfg(not(target_arch = "wasm32"))] + #[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))] #[inline(always)] pub fn consume_file( &self, @@ -1556,7 +1556,7 @@ impl Engine { /// /// Not available under `no_std` or `WASM`. #[cfg(not(feature = "no_std"))] - #[cfg(not(target_arch = "wasm32"))] + #[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))] #[inline(always)] pub fn consume_file_with_scope( &self, diff --git a/src/module/resolvers/mod.rs b/src/module/resolvers/mod.rs index bd94e19e..84b3448f 100644 --- a/src/module/resolvers/mod.rs +++ b/src/module/resolvers/mod.rs @@ -9,11 +9,11 @@ mod collection; pub use collection::ModuleResolversCollection; #[cfg(not(feature = "no_std"))] -#[cfg(not(target_arch = "wasm32"))] +#[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))] mod file; #[cfg(not(feature = "no_std"))] -#[cfg(not(target_arch = "wasm32"))] +#[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))] pub use file::FileModuleResolver; mod stat; diff --git a/src/packages/arithmetic.rs b/src/packages/arithmetic.rs index 4d81eda6..817be5b5 100644 --- a/src/packages/arithmetic.rs +++ b/src/packages/arithmetic.rs @@ -184,7 +184,7 @@ def_package!(crate:ArithmeticPackage:"Basic arithmetic", lib, { reg_functions!(lib += arith_numbers; i8, u8, i16, u16, i32, u32, u64); reg_functions!(lib += signed_numbers; i8, i16, i32); - #[cfg(not(target_arch = "wasm32"))] + #[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))] { reg_functions!(lib += arith_num_128; i128, u128); reg_functions!(lib += signed_num_128; i128); @@ -211,7 +211,7 @@ gen_arithmetic_functions!(arith_numbers => i8, u8, i16, u16, i32, u32, u64); #[cfg(not(feature = "only_i32"))] #[cfg(not(feature = "only_i64"))] -#[cfg(not(target_arch = "wasm32"))] +#[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))] gen_arithmetic_functions!(arith_num_128 => i128, u128); gen_signed_functions!(signed_basic => INT); @@ -222,7 +222,7 @@ gen_signed_functions!(signed_numbers => i8, i16, i32); #[cfg(not(feature = "only_i32"))] #[cfg(not(feature = "only_i64"))] -#[cfg(not(target_arch = "wasm32"))] +#[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))] gen_signed_functions!(signed_num_128 => i128); #[cfg(not(feature = "no_float"))] diff --git a/src/packages/array_basic.rs b/src/packages/array_basic.rs index 95b61dcc..7bd92fdd 100644 --- a/src/packages/array_basic.rs +++ b/src/packages/array_basic.rs @@ -71,7 +71,7 @@ def_package!(crate:BasicArrayPackage:"Basic array utilities.", lib, { { reg_functions!(lib += numbers; i8, u8, i16, u16, i32, i64, u32, u64); - #[cfg(not(target_arch = "wasm32"))] + #[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))] reg_functions!(lib += num_128; i128, u128); } @@ -706,7 +706,7 @@ gen_array_functions!(numbers => i8, u8, i16, u16, i32, i64, u32, u64); #[cfg(not(feature = "only_i32"))] #[cfg(not(feature = "only_i64"))] -#[cfg(not(target_arch = "wasm32"))] +#[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))] gen_array_functions!(num_128 => i128, u128); #[cfg(not(feature = "no_float"))] diff --git a/src/packages/logic.rs b/src/packages/logic.rs index 578234c8..19e7dd2d 100644 --- a/src/packages/logic.rs +++ b/src/packages/logic.rs @@ -62,7 +62,7 @@ def_package!(crate:LogicPackage:"Logical operators.", lib, { { reg_functions!(lib += numbers; i8, u8, i16, u16, i32, u32, u64); - #[cfg(not(target_arch = "wasm32"))] + #[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))] reg_functions!(lib += num_128; i128, u128); } @@ -98,7 +98,7 @@ gen_cmp_functions!(numbers => i8, u8, i16, u16, i32, u32, u64); #[cfg(not(feature = "only_i32"))] #[cfg(not(feature = "only_i64"))] -#[cfg(not(target_arch = "wasm32"))] +#[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))] gen_cmp_functions!(num_128 => i128, u128); #[cfg(not(feature = "no_float"))] diff --git a/src/packages/math_basic.rs b/src/packages/math_basic.rs index 5b8bc8dd..9adb5725 100644 --- a/src/packages/math_basic.rs +++ b/src/packages/math_basic.rs @@ -73,7 +73,7 @@ def_package!(crate:BasicMathPackage:"Basic mathematic functions.", lib, { { reg_functions!(lib += numbers_to_int::to_int(i8, u8, i16, u16, i32, u32, i64, u64)); - #[cfg(not(target_arch = "wasm32"))] + #[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))] reg_functions!(lib += num_128_to_int::to_int(i128, u128)); } @@ -92,7 +92,7 @@ def_package!(crate:BasicMathPackage:"Basic mathematic functions.", lib, { { reg_functions!(lib += numbers_to_float::to_float(i8, u8, i16, u16, i32, u32, i64, u32)); - #[cfg(not(target_arch = "wasm32"))] + #[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))] reg_functions!(lib += num_128_to_float::to_float(i128, u128)); } } @@ -452,7 +452,7 @@ gen_conversion_as_functions!(numbers_to_float => to_float (i8, u8, i16, u16, i32 #[cfg(not(feature = "no_float"))] #[cfg(not(feature = "only_i32"))] #[cfg(not(feature = "only_i64"))] -#[cfg(not(target_arch = "wasm32"))] +#[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))] gen_conversion_as_functions!(num_128_to_float => to_float (i128, u128) -> FLOAT); gen_conversion_as_functions!(basic_to_int => to_int (char) -> INT); @@ -463,7 +463,7 @@ gen_conversion_as_functions!(numbers_to_int => to_int (i8, u8, i16, u16, i32, u3 #[cfg(not(feature = "only_i32"))] #[cfg(not(feature = "only_i64"))] -#[cfg(not(target_arch = "wasm32"))] +#[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))] gen_conversion_as_functions!(num_128_to_int => to_int (i128, u128) -> INT); #[cfg(feature = "decimal")] diff --git a/src/packages/string_basic.rs b/src/packages/string_basic.rs index 2f15e7b2..bbf5e0a1 100644 --- a/src/packages/string_basic.rs +++ b/src/packages/string_basic.rs @@ -62,7 +62,7 @@ def_package!(crate:BasicStringPackage:"Basic string utilities, including printin reg_print_functions!(lib += print_numbers; i8, u8, i16, u16, i32, u32, i64, u64); reg_debug_functions!(lib += debug_numbers; i8, u8, i16, u16, i32, u32, i64, u64); - #[cfg(not(target_arch = "wasm32"))] + #[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))] { reg_print_functions!(lib += print_num_128; i128, u128); reg_debug_functions!(lib += debug_num_128; i128, u128); @@ -128,12 +128,12 @@ gen_functions!(debug_numbers => to_debug(i8, u8, i16, u16, i32, u32, i64, u64)); #[cfg(not(feature = "only_i32"))] #[cfg(not(feature = "only_i64"))] -#[cfg(not(target_arch = "wasm32"))] +#[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))] gen_functions!(print_num_128 => to_string(i128, u128)); #[cfg(not(feature = "only_i32"))] #[cfg(not(feature = "only_i64"))] -#[cfg(not(target_arch = "wasm32"))] +#[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))] gen_functions!(debug_num_128 => to_debug(i128, u128)); #[cfg(not(feature = "no_float"))] diff --git a/src/packages/string_more.rs b/src/packages/string_more.rs index 1a50b32d..05428dc3 100644 --- a/src/packages/string_more.rs +++ b/src/packages/string_more.rs @@ -41,7 +41,7 @@ def_package!(crate:MoreStringPackage:"Additional string utilities, including str { reg_functions!(lib += numbers; i8, u8, i16, u16, i32, i64, u32, u64); - #[cfg(not(target_arch = "wasm32"))] + #[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))] reg_functions!(lib += num_128; i128, u128); } @@ -65,7 +65,7 @@ gen_concat_functions!(numbers => i8, u8, i16, u16, i32, i64, u32, u64); #[cfg(not(feature = "only_i32"))] #[cfg(not(feature = "only_i64"))] -#[cfg(not(target_arch = "wasm32"))] +#[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))] gen_concat_functions!(num_128 => i128, u128); #[cfg(not(feature = "no_float"))] diff --git a/src/packages/time_basic.rs b/src/packages/time_basic.rs index bcd50f55..cfd49fb9 100644 --- a/src/packages/time_basic.rs +++ b/src/packages/time_basic.rs @@ -8,10 +8,10 @@ use crate::{def_package, Dynamic, EvalAltResult, INT}; #[cfg(not(feature = "no_float"))] use crate::FLOAT; -#[cfg(not(target_arch = "wasm32"))] +#[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))] use crate::stdlib::time::{Duration, Instant}; -#[cfg(target_arch = "wasm32")] +#[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))] use instant::{Duration, Instant}; def_package!(crate:BasicTimePackage:"Basic timing utilities.", lib, { @@ -28,12 +28,10 @@ mod time_functions { #[rhai_fn(name = "elapsed", get = "elapsed", return_raw)] pub fn elapsed(timestamp: &mut Instant) -> Result> { #[cfg(not(feature = "no_float"))] - { - if *timestamp > Instant::now() { - Err(make_arithmetic_err("Time-stamp is later than now")) - } else { - Ok((timestamp.elapsed().as_secs_f64() as FLOAT).into()) - } + if *timestamp > Instant::now() { + Err(make_arithmetic_err("Time-stamp is later than now")) + } else { + Ok((timestamp.elapsed().as_secs_f64() as FLOAT).into()) } #[cfg(feature = "no_float")] @@ -56,14 +54,12 @@ mod time_functions { #[rhai_fn(return_raw, name = "-")] pub fn time_diff(ts1: Instant, ts2: Instant) -> Result> { #[cfg(not(feature = "no_float"))] - { - Ok(if ts2 > ts1 { - -(ts2 - ts1).as_secs_f64() as FLOAT - } else { - (ts1 - ts2).as_secs_f64() as FLOAT - } - .into()) + return Ok(if ts2 > ts1 { + -(ts2 - ts1).as_secs_f64() as FLOAT + } else { + (ts1 - ts2).as_secs_f64() as FLOAT } + .into()); #[cfg(feature = "no_float")] if ts2 > ts1 { diff --git a/src/stdlib.rs b/src/stdlib.rs index 0c0e0438..d1aa2f43 100644 --- a/src/stdlib.rs +++ b/src/stdlib.rs @@ -8,7 +8,7 @@ mod inner { pin, prelude, ptr, result, slice, str, task, time, u16, u32, u64, u8, usize, }; - #[cfg(not(target_arch = "wasm32"))] + #[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))] pub use core::{i128, u128}; #[cfg(feature = "sync")] From ac1b7debe983317c48c2e857e0c01a018ba40325 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Fri, 19 Feb 2021 23:13:41 +0800 Subject: [PATCH 4/6] Add pure function attribute. --- codegen/Cargo.toml | 2 +- codegen/src/function.rs | 67 ++++++++++++------ codegen/src/register.rs | 2 +- codegen/src/test/function.rs | 5 ++ codegen/src/test/module.rs | 132 +++++++++++++++++++++++++++++++++++ 5 files changed, 183 insertions(+), 25 deletions(-) diff --git a/codegen/Cargo.toml b/codegen/Cargo.toml index af0b265d..7bcdb878 100644 --- a/codegen/Cargo.toml +++ b/codegen/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rhai_codegen" -version = "0.3.2" +version = "0.3.3" edition = "2018" authors = ["jhwgh1968"] description = "Procedural macro support package for Rhai, a scripting language for Rust" diff --git a/codegen/src/function.rs b/codegen/src/function.rs index 0054a7b7..d3a7f792 100644 --- a/codegen/src/function.rs +++ b/codegen/src/function.rs @@ -106,6 +106,7 @@ pub(crate) fn print_type(ty: &syn::Type) -> String { pub(crate) struct ExportedFnParams { pub name: Vec, pub return_raw: bool, + pub pure: bool, pub skip: bool, pub special: FnSpecialAccess, pub namespace: FnNamespaceAccess, @@ -144,6 +145,7 @@ impl ExportedParams for ExportedFnParams { } = info; let mut name = Vec::new(); let mut return_raw = false; + let mut pure = false; let mut skip = false; let mut namespace = FnNamespaceAccess::Unset; let mut special = FnSpecialAccess::None; @@ -224,6 +226,8 @@ impl ExportedParams for ExportedFnParams { ("index_get", Some(s)) | ("index_set", Some(s)) | ("return_raw", Some(s)) => { return Err(syn::Error::new(s.span(), "extraneous value")) } + ("pure", None) => pure = true, + ("pure", Some(s)) => return Err(syn::Error::new(s.span(), "extraneous value")), ("return_raw", None) => return_raw = true, ("return_raw", Some(s)) => { return Err(syn::Error::new(s.span(), "extraneous value")) @@ -255,6 +259,7 @@ impl ExportedParams for ExportedFnParams { Ok(ExportedFnParams { name, return_raw, + pure, skip, special, namespace, @@ -634,19 +639,19 @@ impl ExportedFn { .map(|r| r.span()) .unwrap_or_else(|| proc_macro2::Span::call_site()); if self.params.return_raw { - quote_spanned! { return_span=> + quote_spanned! { return_span => pub #dynamic_signature { #name(#(#arguments),*) } } } else if self.return_dynamic { - quote_spanned! { return_span=> + quote_spanned! { return_span => pub #dynamic_signature { Ok(#name(#(#arguments),*)) } } } else { - quote_spanned! { return_span=> + quote_spanned! { return_span => pub #dynamic_signature { Ok(Dynamic::from(#name(#(#arguments),*))) } @@ -746,18 +751,33 @@ impl ExportedFn { syn::Type::Reference(syn::TypeReference { ref elem, .. }) => elem.as_ref(), p => p, }; - let downcast_span = quote_spanned!( - arg_type.span()=> &mut args[0usize].write_lock::<#arg_type>().unwrap()); + let downcast_span = quote_spanned!(arg_type.span() => + &mut args[0usize].write_lock::<#arg_type>().unwrap() + ); unpack_statements.push( syn::parse2::(quote! { let #var = #downcast_span; }) .unwrap(), ); + if !self.params().pure { + let arg_lit_str = + syn::LitStr::new(&pat.to_token_stream().to_string(), pat.span()); + unpack_statements.push( + syn::parse2::(quote! { + if args[0usize].is_read_only() { + return Err(Box::new( + EvalAltResult::ErrorAssignmentToConstant(#arg_lit_str.to_string(), Position::NONE) + )); + } + }) + .unwrap(), + ); + } input_type_names.push(arg_name); input_type_exprs.push( - syn::parse2::(quote_spanned!( - arg_type.span()=> TypeId::of::<#arg_type>() + syn::parse2::(quote_spanned!(arg_type.span() => + TypeId::of::<#arg_type>() )) .unwrap(), ); @@ -792,22 +812,25 @@ impl ExportedFn { syn::Type::Path(ref p) if p.path == str_type_path => { is_string = true; is_ref = true; - quote_spanned!(arg_type.span()=> - mem::take(args[#i]).take_immutable_string().unwrap()) + quote_spanned!(arg_type.span() => + mem::take(args[#i]).take_immutable_string().unwrap() + ) } _ => panic!("internal error: why wasn't this found earlier!?"), }, syn::Type::Path(ref p) if p.path == string_type_path => { is_string = true; is_ref = false; - quote_spanned!(arg_type.span()=> - mem::take(args[#i]).take_string().unwrap()) + quote_spanned!(arg_type.span() => + mem::take(args[#i]).take_string().unwrap() + ) } _ => { is_string = false; is_ref = false; - quote_spanned!(arg_type.span()=> - mem::take(args[#i]).cast::<#arg_type>()) + quote_spanned!(arg_type.span() => + mem::take(args[#i]).cast::<#arg_type>() + ) } }; @@ -820,15 +843,15 @@ impl ExportedFn { input_type_names.push(arg_name); if !is_string { input_type_exprs.push( - syn::parse2::(quote_spanned!( - arg_type.span()=> TypeId::of::<#arg_type>() + syn::parse2::(quote_spanned!(arg_type.span() => + TypeId::of::<#arg_type>() )) .unwrap(), ); } else { input_type_exprs.push( - syn::parse2::(quote_spanned!( - arg_type.span()=> TypeId::of::() + syn::parse2::(quote_spanned!(arg_type.span() => + TypeId::of::() )) .unwrap(), ); @@ -860,16 +883,16 @@ impl ExportedFn { .unwrap_or_else(|| proc_macro2::Span::call_site()); let return_expr = if !self.params.return_raw { if self.return_dynamic { - quote_spanned! { return_span=> + quote_spanned! { return_span => Ok(#sig_name(#(#unpack_exprs),*)) } } else { - quote_spanned! { return_span=> + quote_spanned! { return_span => Ok(Dynamic::from(#sig_name(#(#unpack_exprs),*))) } } } else { - quote_spanned! { return_span=> + quote_spanned! { return_span => #sig_name(#(#unpack_exprs),*) } }; @@ -878,9 +901,7 @@ impl ExportedFn { quote! { impl PluginFunction for #type_name { fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result> { - debug_assert_eq!(args.len(), #arg_count, - "wrong arg count: {} != {}", - args.len(), #arg_count); + debug_assert_eq!(args.len(), #arg_count, "wrong arg count: {} != {}", args.len(), #arg_count); #(#unpack_statements)* #return_expr } diff --git a/codegen/src/register.rs b/codegen/src/register.rs index 748baa41..ecd49d1e 100644 --- a/codegen/src/register.rs +++ b/codegen/src/register.rs @@ -33,7 +33,7 @@ pub fn parse_register_macro( )); } let export_name = match &items[1] { - syn::Expr::Lit(lit_str) => quote_spanned!(items[1].span()=> + syn::Expr::Lit(lit_str) => quote_spanned!(items[1].span() => #lit_str.to_string()), expr => quote! { #expr }, }; diff --git a/codegen/src/test/function.rs b/codegen/src/test/function.rs index 1df6e6a2..34e2d38c 100644 --- a/codegen/src/test/function.rs +++ b/codegen/src/test/function.rs @@ -587,6 +587,11 @@ mod generate_tests { fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result> { debug_assert_eq!(args.len(), 2usize, "wrong arg count: {} != {}", args.len(), 2usize); + if args[0usize].is_read_only() { + return Err(Box::new( + EvalAltResult::ErrorAssignmentToConstant("x".to_string(), Position::NONE) + )); + } let arg1 = mem::take(args[1usize]).cast::(); let arg0 = &mut args[0usize].write_lock::().unwrap(); Ok(Dynamic::from(increment(arg0, arg1))) diff --git a/codegen/src/test/module.rs b/codegen/src/test/module.rs index c83f45f6..79f6f872 100644 --- a/codegen/src/test/module.rs +++ b/codegen/src/test/module.rs @@ -1218,6 +1218,83 @@ mod generate_tests { assert_streams_eq(item_mod.generate(), expected_tokens); } + #[test] + fn mut_ref_pure_fn_module() { + let input_tokens: TokenStream = quote! { + pub mod ref_fn { + #[rhai_fn(pure)] + pub fn foo(x: &mut FLOAT, y: INT) -> FLOAT { + *x + y as FLOAT + } + } + }; + + let expected_tokens = quote! { + pub mod ref_fn { + pub fn foo(x: &mut FLOAT, y: INT) -> FLOAT { + *x + y as FLOAT + } + #[allow(unused_imports)] + use super::*; + + pub fn rhai_module_generate() -> Module { + let mut m = Module::new(); + rhai_generate_into_module(&mut m, false); + m.build_index(); + m + } + #[allow(unused_mut)] + pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { + m.set_fn("foo", FnNamespace::Internal, FnAccess::Public, + Some(&["x: &mut FLOAT", "y: INT", "FLOAT"]), &[core::any::TypeId::of::(), core::any::TypeId::of::()], + foo_token().into()); + if flatten {} else {} + } + #[allow(non_camel_case_types)] + struct foo_token(); + impl PluginFunction for foo_token { + fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result> { + debug_assert_eq!(args.len(), 2usize, + "wrong arg count: {} != {}", args.len(), 2usize); + let arg1 = mem::take(args[1usize]).cast::(); + let arg0 = &mut args[0usize].write_lock::().unwrap(); + Ok(Dynamic::from(foo(arg0, arg1))) + } + + fn is_method_call(&self) -> bool { true } + fn is_variadic(&self) -> bool { false } + fn clone_boxed(&self) -> Box { + Box::new(foo_token()) + } + fn input_names(&self) -> Box<[&'static str]> { + new_vec!["x: &mut FLOAT", "y: INT"].into_boxed_slice() + } + fn input_types(&self) -> Box<[TypeId]> { + new_vec![TypeId::of::(), TypeId::of::()].into_boxed_slice() + } + fn return_type(&self) -> &'static str { + "FLOAT" + } + } + pub fn foo_token_callable() -> CallableFunction { + foo_token().into() + } + pub fn foo_token_input_names() -> Box<[&'static str]> { + foo_token().input_names() + } + pub fn foo_token_input_types() -> Box<[TypeId]> { + foo_token().input_types() + } + pub fn foo_token_return_type() -> &'static str { + foo_token().return_type() + } + } + }; + + let item_mod = syn::parse2::(input_tokens).unwrap(); + assert_streams_eq(item_mod.generate(), expected_tokens); + } + #[test] fn one_mut_ref_fn_module() { let input_tokens: TokenStream = quote! { @@ -1255,6 +1332,11 @@ mod generate_tests { fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result> { debug_assert_eq!(args.len(), 1usize, "wrong arg count: {} != {}", args.len(), 1usize); + if args[0usize].is_read_only() { + return Err(Box::new( + EvalAltResult::ErrorAssignmentToConstant("x".to_string(), Position::NONE) + )); + } let arg0 = &mut args[0usize].write_lock::().unwrap(); Ok(Dynamic::from(increment(arg0))) } @@ -1333,6 +1415,11 @@ mod generate_tests { fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result> { debug_assert_eq!(args.len(), 1usize, "wrong arg count: {} != {}", args.len(), 1usize); + if args[0usize].is_read_only() { + return Err(Box::new( + EvalAltResult::ErrorAssignmentToConstant("x".to_string(), Position::NONE) + )); + } let arg0 = &mut args[0usize].write_lock::().unwrap(); Ok(Dynamic::from(increment(arg0))) } @@ -1432,6 +1519,11 @@ mod generate_tests { fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result> { debug_assert_eq!(args.len(), 1usize, "wrong arg count: {} != {}", args.len(), 1usize); + if args[0usize].is_read_only() { + return Err(Box::new( + EvalAltResult::ErrorAssignmentToConstant("x".to_string(), Position::NONE) + )); + } let arg0 = &mut args[0usize].write_lock::().unwrap(); Ok(Dynamic::from(increment(arg0))) } @@ -1530,6 +1622,11 @@ mod generate_tests { fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result> { debug_assert_eq!(args.len(), 1usize, "wrong arg count: {} != {}", args.len(), 1usize); + if args[0usize].is_read_only() { + return Err(Box::new( + EvalAltResult::ErrorAssignmentToConstant("x".to_string(), Position::NONE) + )); + } let arg0 = &mut args[0usize].write_lock::().unwrap(); Ok(Dynamic::from(int_foo(arg0))) } @@ -1607,6 +1704,11 @@ mod generate_tests { fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result> { debug_assert_eq!(args.len(), 1usize, "wrong arg count: {} != {}", args.len(), 1usize); + if args[0usize].is_read_only() { + return Err(Box::new( + EvalAltResult::ErrorAssignmentToConstant("x".to_string(), Position::NONE) + )); + } let arg0 = &mut args[0usize].write_lock::().unwrap(); Ok(Dynamic::from(int_foo(arg0))) } @@ -1683,6 +1785,11 @@ mod generate_tests { fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result> { debug_assert_eq!(args.len(), 2usize, "wrong arg count: {} != {}", args.len(), 2usize); + if args[0usize].is_read_only() { + return Err(Box::new( + EvalAltResult::ErrorAssignmentToConstant("x".to_string(), Position::NONE) + )); + } let arg1 = mem::take(args[1usize]).cast::(); let arg0 = &mut args[0usize].write_lock::().unwrap(); Ok(Dynamic::from(int_foo(arg0, arg1))) @@ -1763,6 +1870,11 @@ mod generate_tests { fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result> { debug_assert_eq!(args.len(), 2usize, "wrong arg count: {} != {}", args.len(), 2usize); + if args[0usize].is_read_only() { + return Err(Box::new( + EvalAltResult::ErrorAssignmentToConstant("x".to_string(), Position::NONE) + )); + } let arg1 = mem::take(args[1usize]).cast::(); let arg0 = &mut args[0usize].write_lock::().unwrap(); Ok(Dynamic::from(int_foo(arg0, arg1))) @@ -1842,6 +1954,11 @@ mod generate_tests { fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result> { debug_assert_eq!(args.len(), 2usize, "wrong arg count: {} != {}", args.len(), 2usize); + if args[0usize].is_read_only() { + return Err(Box::new( + EvalAltResult::ErrorAssignmentToConstant("x".to_string(), Position::NONE) + )); + } let arg1 = mem::take(args[1usize]).cast::(); let arg0 = &mut args[0usize].write_lock::().unwrap(); Ok(Dynamic::from(get_by_index(arg0, arg1))) @@ -1927,6 +2044,11 @@ mod generate_tests { fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result> { debug_assert_eq!(args.len(), 2usize, "wrong arg count: {} != {}", args.len(), 2usize); + if args[0usize].is_read_only() { + return Err(Box::new( + EvalAltResult::ErrorAssignmentToConstant("x".to_string(), Position::NONE) + )); + } let arg1 = mem::take(args[1usize]).cast::(); let arg0 = &mut args[0usize].write_lock::().unwrap(); Ok(Dynamic::from(get_by_index(arg0, arg1))) @@ -2008,6 +2130,11 @@ mod generate_tests { fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result> { debug_assert_eq!(args.len(), 3usize, "wrong arg count: {} != {}", args.len(), 3usize); + if args[0usize].is_read_only() { + return Err(Box::new( + EvalAltResult::ErrorAssignmentToConstant("x".to_string(), Position::NONE) + )); + } let arg1 = mem::take(args[1usize]).cast::(); let arg2 = mem::take(args[2usize]).cast::(); let arg0 = &mut args[0usize].write_lock::().unwrap(); @@ -2097,6 +2224,11 @@ mod generate_tests { fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result> { debug_assert_eq!(args.len(), 3usize, "wrong arg count: {} != {}", args.len(), 3usize); + if args[0usize].is_read_only() { + return Err(Box::new( + EvalAltResult::ErrorAssignmentToConstant("x".to_string(), Position::NONE) + )); + } let arg1 = mem::take(args[1usize]).cast::(); let arg2 = mem::take(args[2usize]).cast::(); let arg0 = &mut args[0usize].write_lock::().unwrap(); From 182fc2c3d12c619f19245663deb9ac9cc053a944 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Fri, 19 Feb 2021 23:13:53 +0800 Subject: [PATCH 5/6] Check for constant values passed to methods. --- Cargo.toml | 2 +- README.md | 3 +- RELEASES.md | 1 + src/optimize.rs | 2 +- src/packages/array_basic.rs | 224 +++++++++++++++++------------------ src/packages/fn_basic.rs | 4 +- src/packages/iter_basic.rs | 19 ++- src/packages/map_basic.rs | 38 +++--- src/packages/string_basic.rs | 26 ++-- src/packages/string_more.rs | 208 ++++++++++++++++++-------------- src/packages/time_basic.rs | 127 +++++++++++--------- src/plugin.rs | 2 +- src/result.rs | 4 +- 13 files changed, 360 insertions(+), 300 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c1bff9aa..fe3dffdc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,7 @@ categories = [ "no-std", "embedded", "wasm", "parser-implementations" ] [dependencies] smallvec = { version = "1.6", default-features = false, features = ["union"] } ahash = { version = "0.6", default-features = false } -rhai_codegen = { version = "0.3", path = "codegen" } +rhai_codegen = { version = "0.3.3", path = "codegen" } [features] default = [] diff --git a/README.md b/README.md index e256214f..628108e8 100644 --- a/README.md +++ b/README.md @@ -32,11 +32,12 @@ Standard features * Fairly efficient evaluation (1 million iterations in 0.3 sec on a single-core, 2.3 GHz Linux VM). * Tight integration with native Rust [functions](https://rhai.rs/book/rust/functions.html) and [types]([#custom-types-and-methods](https://rhai.rs/book/rust/custom.html)), including [getters/setters](https://rhai.rs/book/rust/getters-setters.html), [methods](https://rhai.rs/book/rust/custom.html) and [indexers](https://rhai.rs/book/rust/indexers.html). * Freely pass Rust variables/constants into a script via an external [`Scope`](https://rhai.rs/book/rust/scope.html) - all clonable Rust types are supported; no need to implement any special trait. +* Built-in support for most common [data types](https://rhai.rs/book/language/values-and-types.html) including booleans, integers, floating-point numbers (including [`Decimal`](https://crates.io/crates/rust_decimal)), strings, Unicode characters, arrays and maps. * Easily [call a script-defined function](https://rhai.rs/book/engine/call-fn.html) from Rust. * Relatively little `unsafe` code (yes there are some for performance reasons). * Few dependencies (currently only [`smallvec`](https://crates.io/crates/smallvec) and [`ahash`](https://crates.io/crates/ahash)). * Re-entrant scripting engine can be made `Send + Sync` (via the `sync` feature). -* Compile once to AST form for repeated evaluations. +* Compile once to [AST](https://rhai.rs/book/engine/compile.html) form for repeated evaluations. * Scripts are [optimized](https://rhai.rs/book/engine/optimize.html) (useful for template-based machine-generated scripts). * Easy custom API development via [plugins](https://rhai.rs/book/plugins/index.html) system powered by procedural macros. * [Function overloading](https://rhai.rs/book/language/overload.html) and [operator overloading](https://rhai.rs/book/rust/operators.html). diff --git a/RELEASES.md b/RELEASES.md index 34b1b597..2bc2a021 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -12,6 +12,7 @@ Bug fixes New features ------------ +* `#[rhai_fn(pure)]` attribute to mark a plugin function with `&mut` parameter as _pure_ so constants can be passed to it. Without it, passing a constant value into the `&mut` parameter will now raise an error. * Comparisons between `FLOAT`/[`Decimal`](https://crates.io/crates/rust_decimal) and `INT` are now built in. Enhancements diff --git a/src/optimize.rs b/src/optimize.rs index 7a7296b4..4fa5d960 100644 --- a/src/optimize.rs +++ b/src/optimize.rs @@ -575,7 +575,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut State) { Expr::Array(x, _) => x.iter_mut().for_each(|expr| optimize_expr(expr, state)), // #{ key:constant, .. } #[cfg(not(feature = "no_object"))] - Expr::Map(_, _) if expr.is_constant()=> { + Expr::Map(_, _) if expr.is_constant() => { state.set_dirty(); *expr = Expr::DynamicConstant(Box::new(expr.get_constant_value().unwrap()), expr.position()); } diff --git a/src/packages/array_basic.rs b/src/packages/array_basic.rs index 7bd92fdd..bb1258d1 100644 --- a/src/packages/array_basic.rs +++ b/src/packages/array_basic.rs @@ -22,22 +22,22 @@ macro_rules! gen_array_functions { #[export_module] pub mod functions { #[rhai_fn(name = "push", name = "+=")] - pub fn push(list: &mut Array, item: $arg_type) { - list.push(Dynamic::from(item)); + pub fn push(array: &mut Array, item: $arg_type) { + array.push(Dynamic::from(item)); } - pub fn insert(list: &mut Array, position: INT, item: $arg_type) { + pub fn insert(array: &mut Array, position: INT, item: $arg_type) { if position <= 0 { - list.insert(0, Dynamic::from(item)); - } else if (position as usize) >= list.len() { - push(list, item); + array.insert(0, Dynamic::from(item)); + } else if (position as usize) >= array.len() { + push(array, item); } else { - list.insert(position as usize, Dynamic::from(item)); + array.insert(position as usize, Dynamic::from(item)); } } #[rhai_fn(return_raw)] - pub fn pad(_ctx: NativeCallContext, list: &mut Array, len: INT, item: $arg_type) -> Result> { + pub fn pad(_ctx: NativeCallContext, array: &mut Array, len: INT, item: $arg_type) -> Result> { // Check if array will be over max size limit #[cfg(not(feature = "unchecked"))] if _ctx.engine().max_array_size() > 0 && len > 0 && (len as usize) > _ctx.engine().max_array_size() { @@ -46,8 +46,8 @@ macro_rules! gen_array_functions { ).into(); } - if len > 0 && len as usize > list.len() { - list.resize(len as usize, Dynamic::from(item)); + if len > 0 && len as usize > array.len() { + array.resize(len as usize, Dynamic::from(item)); } Ok(Dynamic::UNIT) @@ -90,117 +90,117 @@ def_package!(crate:BasicArrayPackage:"Basic array utilities.", lib, { #[export_module] mod array_functions { - #[rhai_fn(name = "len", get = "len")] - pub fn len(list: &mut Array) -> INT { - list.len() as INT + #[rhai_fn(name = "len", get = "len", pure)] + pub fn len(array: &mut Array) -> INT { + array.len() as INT } #[rhai_fn(name = "append", name = "+=")] - pub fn append(x: &mut Array, y: Array) { - x.extend(y); + pub fn append(array: &mut Array, y: Array) { + array.extend(y); } #[rhai_fn(name = "+")] - pub fn concat(mut x: Array, y: Array) -> Array { - x.extend(y); - x + pub fn concat(mut array: Array, y: Array) -> Array { + array.extend(y); + array } - pub fn pop(list: &mut Array) -> Dynamic { - list.pop().unwrap_or_else(|| ().into()) + pub fn pop(array: &mut Array) -> Dynamic { + array.pop().unwrap_or_else(|| ().into()) } - pub fn shift(list: &mut Array) -> Dynamic { - if list.is_empty() { + pub fn shift(array: &mut Array) -> Dynamic { + if array.is_empty() { ().into() } else { - list.remove(0) + array.remove(0) } } - pub fn remove(list: &mut Array, len: INT) -> Dynamic { - if len < 0 || (len as usize) >= list.len() { + pub fn remove(array: &mut Array, len: INT) -> Dynamic { + if len < 0 || (len as usize) >= array.len() { ().into() } else { - list.remove(len as usize) + array.remove(len as usize) } } - pub fn clear(list: &mut Array) { - list.clear(); + pub fn clear(array: &mut Array) { + array.clear(); } - pub fn truncate(list: &mut Array, len: INT) { + pub fn truncate(array: &mut Array, len: INT) { if len >= 0 { - list.truncate(len as usize); + array.truncate(len as usize); } else { - list.clear(); + array.clear(); } } - pub fn chop(list: &mut Array, len: INT) { - if len as usize >= list.len() { + pub fn chop(array: &mut Array, len: INT) { + if len as usize >= array.len() { } else if len >= 0 { - list.drain(0..list.len() - len as usize); + array.drain(0..array.len() - len as usize); } else { - list.clear(); + array.clear(); } } - pub fn reverse(list: &mut Array) { - list.reverse(); + pub fn reverse(array: &mut Array) { + array.reverse(); } - pub fn splice(list: &mut Array, start: INT, len: INT, replace: Array) { + pub fn splice(array: &mut Array, start: INT, len: INT, replace: Array) { let start = if start < 0 { 0 - } else if start as usize >= list.len() { - list.len() - 1 + } else if start as usize >= array.len() { + array.len() - 1 } else { start as usize }; let len = if len < 0 { 0 - } else if len as usize > list.len() - start { - list.len() - start + } else if len as usize > array.len() - start { + array.len() - start } else { len as usize }; - list.splice(start..start + len, replace.into_iter()); + array.splice(start..start + len, replace.into_iter()); } - pub fn extract(list: &mut Array, start: INT, len: INT) -> Array { + pub fn extract(array: &mut Array, start: INT, len: INT) -> Array { let start = if start < 0 { 0 - } else if start as usize >= list.len() { - list.len() - 1 + } else if start as usize >= array.len() { + array.len() - 1 } else { start as usize }; let len = if len < 0 { 0 - } else if len as usize > list.len() - start { - list.len() - start + } else if len as usize > array.len() - start { + array.len() - start } else { len as usize }; - list[start..start + len].iter().cloned().collect() + array[start..start + len].iter().cloned().collect() } #[rhai_fn(name = "extract")] - pub fn extract_tail(list: &mut Array, start: INT) -> Array { + pub fn extract_tail(array: &mut Array, start: INT) -> Array { let start = if start < 0 { 0 - } else if start as usize >= list.len() { - list.len() - 1 + } else if start as usize >= array.len() { + array.len() - 1 } else { start as usize }; - list[start..].iter().cloned().collect() + array[start..].iter().cloned().collect() } #[rhai_fn(return_raw)] pub fn map( ctx: NativeCallContext, - list: &mut Array, + array: &mut Array, mapper: FnPtr, ) -> Result> { - let mut array = Array::with_capacity(max(TYPICAL_ARRAY_SIZE, list.len())); + let mut ar = Array::with_capacity(max(TYPICAL_ARRAY_SIZE, array.len())); - for (i, item) in list.iter().enumerate() { - array.push( + for (i, item) in array.iter().enumerate() { + ar.push( mapper .call_dynamic(ctx, None, [item.clone()]) .or_else(|err| match *err { @@ -222,17 +222,17 @@ mod array_functions { ); } - Ok(array.into()) + Ok(ar.into()) } #[rhai_fn(return_raw)] pub fn filter( ctx: NativeCallContext, - list: &mut Array, + array: &mut Array, filter: FnPtr, ) -> Result> { - let mut array = Array::with_capacity(max(TYPICAL_ARRAY_SIZE, list.len())); + let mut ar = Array::with_capacity(max(TYPICAL_ARRAY_SIZE, array.len())); - for (i, item) in list.iter().enumerate() { + for (i, item) in array.iter().enumerate() { if filter .call_dynamic(ctx, None, [item.clone()]) .or_else(|err| match *err { @@ -254,19 +254,19 @@ mod array_functions { .as_bool() .unwrap_or(false) { - array.push(item.clone()); + ar.push(item.clone()); } } - Ok(array.into()) + Ok(ar.into()) } #[rhai_fn(return_raw)] pub fn index_of( ctx: NativeCallContext, - list: &mut Array, + array: &mut Array, filter: FnPtr, ) -> Result> { - for (i, item) in list.iter().enumerate() { + for (i, item) in array.iter().enumerate() { if filter .call_dynamic(ctx, None, [item.clone()]) .or_else(|err| match *err { @@ -297,10 +297,10 @@ mod array_functions { #[rhai_fn(return_raw)] pub fn some( ctx: NativeCallContext, - list: &mut Array, + array: &mut Array, filter: FnPtr, ) -> Result> { - for (i, item) in list.iter().enumerate() { + for (i, item) in array.iter().enumerate() { if filter .call_dynamic(ctx, None, [item.clone()]) .or_else(|err| match *err { @@ -331,10 +331,10 @@ mod array_functions { #[rhai_fn(return_raw)] pub fn all( ctx: NativeCallContext, - list: &mut Array, + array: &mut Array, filter: FnPtr, ) -> Result> { - for (i, item) in list.iter().enumerate() { + for (i, item) in array.iter().enumerate() { if !filter .call_dynamic(ctx, None, [item.clone()]) .or_else(|err| match *err { @@ -365,12 +365,12 @@ mod array_functions { #[rhai_fn(return_raw)] pub fn reduce( ctx: NativeCallContext, - list: &mut Array, + array: &mut Array, reducer: FnPtr, ) -> Result> { let mut result: Dynamic = Dynamic::UNIT; - for (i, item) in list.iter().enumerate() { + for (i, item) in array.iter().enumerate() { result = reducer .call_dynamic(ctx, None, [result.clone(), item.clone()]) .or_else(|err| match *err { @@ -396,7 +396,7 @@ mod array_functions { #[rhai_fn(name = "reduce", return_raw)] pub fn reduce_with_initial( ctx: NativeCallContext, - list: &mut Array, + array: &mut Array, reducer: FnPtr, initial: FnPtr, ) -> Result> { @@ -409,7 +409,7 @@ mod array_functions { )) })?; - for (i, item) in list.iter().enumerate() { + for (i, item) in array.iter().enumerate() { result = reducer .call_dynamic(ctx, None, [result.clone(), item.clone()]) .or_else(|err| match *err { @@ -435,12 +435,12 @@ mod array_functions { #[rhai_fn(return_raw)] pub fn reduce_rev( ctx: NativeCallContext, - list: &mut Array, + array: &mut Array, reducer: FnPtr, ) -> Result> { let mut result: Dynamic = Dynamic::UNIT; - for (i, item) in list.iter().enumerate().rev() { + for (i, item) in array.iter().enumerate().rev() { result = reducer .call_dynamic(ctx, None, [result.clone(), item.clone()]) .or_else(|err| match *err { @@ -466,7 +466,7 @@ mod array_functions { #[rhai_fn(name = "reduce_rev", return_raw)] pub fn reduce_rev_with_initial( ctx: NativeCallContext, - list: &mut Array, + array: &mut Array, reducer: FnPtr, initial: FnPtr, ) -> Result> { @@ -479,7 +479,7 @@ mod array_functions { )) })?; - for (i, item) in list.iter().enumerate().rev() { + for (i, item) in array.iter().enumerate().rev() { result = reducer .call_dynamic(ctx, None, [result.clone(), item.clone()]) .or_else(|err| match *err { @@ -505,10 +505,10 @@ mod array_functions { #[rhai_fn(return_raw)] pub fn sort( ctx: NativeCallContext, - list: &mut Array, + array: &mut Array, comparer: FnPtr, ) -> Result> { - list.sort_by(|x, y| { + array.sort_by(|x, y| { comparer .call_dynamic(ctx, None, [x.clone(), y.clone()]) .ok() @@ -541,23 +541,23 @@ mod array_functions { #[rhai_fn(return_raw)] pub fn drain( ctx: NativeCallContext, - list: &mut Array, + array: &mut Array, filter: FnPtr, ) -> Result> { - let mut drained = Array::with_capacity(max(TYPICAL_ARRAY_SIZE, list.len())); + let mut drained = Array::with_capacity(max(TYPICAL_ARRAY_SIZE, array.len())); - let mut i = list.len(); + let mut i = array.len(); while i > 0 { i -= 1; if filter - .call_dynamic(ctx, None, [list[i].clone()]) + .call_dynamic(ctx, None, [array[i].clone()]) .or_else(|err| match *err { EvalAltResult::ErrorFunctionNotFound(fn_sig, _) if fn_sig.starts_with(filter.fn_name()) => { - filter.call_dynamic(ctx, None, [list[i].clone(), (i as INT).into()]) + filter.call_dynamic(ctx, None, [array[i].clone(), (i as INT).into()]) } _ => Err(err), }) @@ -572,52 +572,52 @@ mod array_functions { .as_bool() .unwrap_or(false) { - drained.push(list.remove(i)); + drained.push(array.remove(i)); } } Ok(drained.into()) } #[rhai_fn(name = "drain")] - pub fn drain_range(list: &mut Array, start: INT, len: INT) -> Array { + pub fn drain_range(array: &mut Array, start: INT, len: INT) -> Array { let start = if start < 0 { 0 - } else if start as usize >= list.len() { - list.len() - 1 + } else if start as usize >= array.len() { + array.len() - 1 } else { start as usize }; let len = if len < 0 { 0 - } else if len as usize > list.len() - start { - list.len() - start + } else if len as usize > array.len() - start { + array.len() - start } else { len as usize }; - list.drain(start..start + len - 1).collect() + array.drain(start..start + len - 1).collect() } #[rhai_fn(return_raw)] pub fn retain( ctx: NativeCallContext, - list: &mut Array, + array: &mut Array, filter: FnPtr, ) -> Result> { - let mut drained = Array::with_capacity(max(TYPICAL_ARRAY_SIZE, list.len())); + let mut drained = Array::with_capacity(max(TYPICAL_ARRAY_SIZE, array.len())); - let mut i = list.len(); + let mut i = array.len(); while i > 0 { i -= 1; if !filter - .call_dynamic(ctx, None, [list[i].clone()]) + .call_dynamic(ctx, None, [array[i].clone()]) .or_else(|err| match *err { EvalAltResult::ErrorFunctionNotFound(fn_sig, _) if fn_sig.starts_with(filter.fn_name()) => { - filter.call_dynamic(ctx, None, [list[i].clone(), (i as INT).into()]) + filter.call_dynamic(ctx, None, [array[i].clone(), (i as INT).into()]) } _ => Err(err), }) @@ -632,51 +632,51 @@ mod array_functions { .as_bool() .unwrap_or(false) { - drained.push(list.remove(i)); + drained.push(array.remove(i)); } } Ok(drained.into()) } #[rhai_fn(name = "retain")] - pub fn retain_range(list: &mut Array, start: INT, len: INT) -> Array { + pub fn retain_range(array: &mut Array, start: INT, len: INT) -> Array { let start = if start < 0 { 0 - } else if start as usize >= list.len() { - list.len() - 1 + } else if start as usize >= array.len() { + array.len() - 1 } else { start as usize }; let len = if len < 0 { 0 - } else if len as usize > list.len() - start { - list.len() - start + } else if len as usize > array.len() - start { + array.len() - start } else { len as usize }; - let mut drained = list.drain(start + len..).collect::(); - drained.extend(list.drain(..start)); + let mut drained = array.drain(start + len..).collect::(); + drained.extend(array.drain(..start)); drained } #[rhai_fn(name = "==", return_raw)] pub fn equals( ctx: NativeCallContext, - arr1: &mut Array, - mut arr2: Array, + array: &mut Array, + mut array2: Array, ) -> Result> { - if arr1.len() != arr2.len() { + if array.len() != array2.len() { return Ok(false.into()); } - if arr1.is_empty() { + if array.is_empty() { return Ok(true.into()); } let def_value = Some(false.into()); - for (a1, a2) in arr1.iter_mut().zip(arr2.iter_mut()) { + for (a1, a2) in array.iter_mut().zip(array2.iter_mut()) { let equals = ctx .call_fn_dynamic_raw(OP_EQUALS, true, false, &mut [a1, a2], def_value.as_ref()) .map(|v| v.as_bool().unwrap_or(false))?; @@ -691,10 +691,10 @@ mod array_functions { #[rhai_fn(name = "!=", return_raw)] pub fn not_equals( ctx: NativeCallContext, - arr1: &mut Array, - arr2: Array, + array: &mut Array, + array2: Array, ) -> Result> { - equals(ctx, arr1, arr2).map(|r| (!r.as_bool().unwrap()).into()) + equals(ctx, array, array2).map(|r| (!r.as_bool().unwrap()).into()) } } diff --git a/src/packages/fn_basic.rs b/src/packages/fn_basic.rs index c2943498..86185215 100644 --- a/src/packages/fn_basic.rs +++ b/src/packages/fn_basic.rs @@ -12,7 +12,7 @@ def_package!(crate:BasicFnPackage:"Basic Fn functions.", lib, { #[export_module] mod fn_ptr_functions { - #[rhai_fn(name = "name", get = "name")] + #[rhai_fn(name = "name", get = "name", pure)] pub fn name(f: &mut FnPtr) -> ImmutableString { f.get_fn_name().clone() } @@ -21,7 +21,7 @@ mod fn_ptr_functions { pub mod functions { use crate::{calc_script_fn_hash, stdlib::iter::empty, INT}; - #[rhai_fn(name = "is_anonymous", get = "is_anonymous")] + #[rhai_fn(name = "is_anonymous", get = "is_anonymous", pure)] pub fn is_anonymous(f: &mut FnPtr) -> bool { f.is_anonymous() } diff --git a/src/packages/iter_basic.rs b/src/packages/iter_basic.rs index f2e839da..4d48ffd8 100644 --- a/src/packages/iter_basic.rs +++ b/src/packages/iter_basic.rs @@ -60,7 +60,7 @@ macro_rules! reg_range { #[cfg(not(feature = "only_i32"))] #[cfg(not(feature = "only_i64"))] -macro_rules! reg_step { +macro_rules! reg_stepped_range { ($lib:expr, $x:expr, $( $y:ty ),*) => ( $( $lib.set_iterator::>(); @@ -68,38 +68,35 @@ macro_rules! reg_step { $lib.update_fn_metadata(hash, [ concat!("from: ", stringify!($y)), concat!("to: ", stringify!($y)), - concat!("step: ", stringify!($y)), concat!("Iterator") + concat!("step: ", stringify!($y)), + concat!("Iterator") ]); )* ) } def_package!(crate:BasicIteratorPackage:"Basic range iterators.", lib, { - lib.set_iterator::>(); - let hash = lib.set_fn_2("range", get_range::); - lib.update_fn_metadata(hash, ["from: INT", "to: INT", "Iterator"]); + reg_range!(lib, "range", INT); #[cfg(not(feature = "only_i32"))] #[cfg(not(feature = "only_i64"))] { - reg_range!(lib, "range", i8, u8, i16, u16, i32, i64, u32, u64); + reg_range!(lib, "range", i8, u8, i16, u16, i32, u32, i64, u64); if cfg!(not(target_arch = "wasm32")) { reg_range!(lib, "range", i128, u128); } } - lib.set_iterator::>(); - let hash = lib.set_fn_3("range", get_step_range::); - lib.update_fn_metadata(hash, ["from: INT", "to: INT", "step: INT", "Iterator"]); + reg_stepped_range!(lib, "range", INT); #[cfg(not(feature = "only_i32"))] #[cfg(not(feature = "only_i64"))] { - reg_step!(lib, "range", i8, u8, i16, u16, i32, i64, u32, u64); + reg_stepped_range!(lib, "range", i8, u8, i16, u16, i32, u32, i64, u64); if cfg!(not(target_arch = "wasm32")) { - reg_step!(lib, "range", i128, u128); + reg_stepped_range!(lib, "range", i128, u128); } } }); diff --git a/src/packages/map_basic.rs b/src/packages/map_basic.rs index fd328c7b..c2f45281 100644 --- a/src/packages/map_basic.rs +++ b/src/packages/map_basic.rs @@ -13,52 +13,54 @@ def_package!(crate:BasicMapPackage:"Basic object map utilities.", lib, { #[export_module] mod map_functions { + #[rhai_fn(pure)] pub fn has(map: &mut Map, prop: ImmutableString) -> bool { map.contains_key(&prop) } + #[rhai_fn(pure)] pub fn len(map: &mut Map) -> INT { map.len() as INT } pub fn clear(map: &mut Map) { map.clear(); } - pub fn remove(x: &mut Map, name: ImmutableString) -> Dynamic { - x.remove(&name).unwrap_or_else(|| ().into()) + pub fn remove(map: &mut Map, name: ImmutableString) -> Dynamic { + map.remove(&name).unwrap_or_else(|| ().into()) } #[rhai_fn(name = "mixin", name = "+=")] - pub fn mixin(map1: &mut Map, map2: Map) { + pub fn mixin(map: &mut Map, map2: Map) { map2.into_iter().for_each(|(key, value)| { - map1.insert(key, value); + map.insert(key, value); }); } #[rhai_fn(name = "+")] - pub fn merge(mut map1: Map, map2: Map) -> Map { + pub fn merge(mut map: Map, map2: Map) -> Map { map2.into_iter().for_each(|(key, value)| { - map1.insert(key, value); + map.insert(key, value); }); - map1 + map } - pub fn fill_with(map1: &mut Map, map2: Map) { + pub fn fill_with(map: &mut Map, map2: Map) { map2.into_iter().for_each(|(key, value)| { - map1.entry(key).or_insert(value); + map.entry(key).or_insert(value); }); } - #[rhai_fn(name = "==", return_raw)] + #[rhai_fn(name = "==", return_raw, pure)] pub fn equals( ctx: NativeCallContext, - map1: &mut Map, + map: &mut Map, mut map2: Map, ) -> Result> { - if map1.len() != map2.len() { + if map.len() != map2.len() { return Ok(false.into()); } - if map1.is_empty() { + if map.is_empty() { return Ok(true.into()); } let def_value = Some(false.into()); - for (m1, v1) in map1.iter_mut() { + for (m1, v1) in map.iter_mut() { if let Some(v2) = map2.get_mut(m1) { let equals = ctx .call_fn_dynamic_raw(OP_EQUALS, true, false, &mut [v1, v2], def_value.as_ref()) @@ -74,20 +76,22 @@ mod map_functions { Ok(true.into()) } - #[rhai_fn(name = "!=", return_raw)] + #[rhai_fn(name = "!=", return_raw, pure)] pub fn not_equals( ctx: NativeCallContext, - map1: &mut Map, + map: &mut Map, map2: Map, ) -> Result> { - equals(ctx, map1, map2).map(|r| (!r.as_bool().unwrap()).into()) + equals(ctx, map, map2).map(|r| (!r.as_bool().unwrap()).into()) } #[cfg(not(feature = "no_index"))] pub mod indexing { + #[rhai_fn(pure)] pub fn keys(map: &mut Map) -> Array { map.iter().map(|(k, _)| k.clone().into()).collect() } + #[rhai_fn(pure)] pub fn values(map: &mut Map) -> Array { map.iter().map(|(_, v)| v.clone()).collect() } diff --git a/src/packages/string_basic.rs b/src/packages/string_basic.rs index bbf5e0a1..4024cf2f 100644 --- a/src/packages/string_basic.rs +++ b/src/packages/string_basic.rs @@ -28,7 +28,7 @@ macro_rules! gen_functions { pub mod $root { $(pub mod $arg_type { use super::super::*; - #[export_fn] + #[export_fn(pure)] pub fn to_string_func(x: &mut $arg_type) -> ImmutableString { super::super::$fn_name(x) } @@ -174,7 +174,7 @@ mod print_debug_functions { pub fn print_string(s: ImmutableString) -> ImmutableString { s } - #[rhai_fn(name = "debug")] + #[rhai_fn(name = "debug", pure)] pub fn debug_fn_ptr(f: &mut FnPtr) -> ImmutableString { to_string(f) } @@ -183,14 +183,20 @@ mod print_debug_functions { pub mod array_functions { use super::*; - #[rhai_fn(name = "print", name = "to_string", name = "to_debug", name = "debug")] - pub fn format_array(ctx: NativeCallContext, arr: &mut Array) -> ImmutableString { + #[rhai_fn( + name = "print", + name = "to_string", + name = "to_debug", + name = "debug", + pure + )] + pub fn format_array(ctx: NativeCallContext, array: &mut Array) -> ImmutableString { let mut result = crate::stdlib::string::String::with_capacity(16); result.push_str("["); - let len = arr.len(); + let len = array.len(); - arr.iter_mut().enumerate().for_each(|(i, x)| { + array.iter_mut().enumerate().for_each(|(i, x)| { result.push_str(&print_with_func(FUNC_TO_DEBUG, &ctx, x)); if i < len - 1 { result.push_str(", "); @@ -205,7 +211,13 @@ mod print_debug_functions { pub mod map_functions { use super::*; - #[rhai_fn(name = "print", name = "to_string", name = "to_debug", name = "debug")] + #[rhai_fn( + name = "print", + name = "to_string", + name = "to_debug", + name = "debug", + pure + )] pub fn format_map(ctx: NativeCallContext, map: &mut Map) -> ImmutableString { let mut result = crate::stdlib::string::String::with_capacity(16); result.push_str("#{"); diff --git a/src/packages/string_more.rs b/src/packages/string_more.rs index 05428dc3..65032da2 100644 --- a/src/packages/string_more.rs +++ b/src/packages/string_more.rs @@ -14,13 +14,13 @@ macro_rules! gen_concat_functions { #[export_module] pub mod functions { #[rhai_fn(name = "+")] - pub fn append_func(x: &str, y: $arg_type) -> String { - format!("{}{}", x, y) + pub fn append_func(string: &str, arg: $arg_type) -> String { + format!("{}{}", string, arg) } - #[rhai_fn(name = "+")] - pub fn prepend_func(x: &mut $arg_type, y: &str) -> String { - format!("{}{}", x, y) + #[rhai_fn(name = "+", pure)] + pub fn prepend_func(arg: &mut $arg_type, string: &str) -> String { + format!("{}{}", arg, string) } } } )* } @@ -53,7 +53,7 @@ def_package!(crate:MoreStringPackage:"Additional string utilities, including str // Register string iterator lib.set_iter( TypeId::of::(), - |s: Dynamic| Box::new(s.cast::().chars().collect::>().into_iter().map(Into::into)) + |string: Dynamic| Box::new(string.cast::().chars().collect::>().into_iter().map(Into::into)) ); }); @@ -73,104 +73,116 @@ gen_concat_functions!(float => f32, f64); #[export_module] mod string_functions { + use crate::ImmutableString; + #[rhai_fn(name = "+")] - pub fn add_append_unit(s: ImmutableString, _x: ()) -> ImmutableString { - s + pub fn add_append_unit(string: ImmutableString, _x: ()) -> ImmutableString { + string } #[rhai_fn(name = "+")] - pub fn add_prepend_unit(_x: (), s: ImmutableString) -> ImmutableString { - s + pub fn add_prepend_unit(_x: (), string: ImmutableString) -> ImmutableString { + string } #[rhai_fn(name = "len", get = "len")] - pub fn len(s: &str) -> INT { - s.chars().count() as INT + pub fn len(string: &str) -> INT { + string.chars().count() as INT } - pub fn clear(s: &mut ImmutableString) { - s.make_mut().clear(); + pub fn clear(string: &mut ImmutableString) { + string.make_mut().clear(); } - pub fn truncate(s: &mut ImmutableString, len: INT) { + pub fn truncate(string: &mut ImmutableString, len: INT) { if len > 0 { - let chars: StaticVec<_> = s.chars().collect(); - let copy = s.make_mut(); + let chars: StaticVec<_> = string.chars().collect(); + let copy = string.make_mut(); copy.clear(); copy.extend(chars.into_iter().take(len as usize)); } else { - s.make_mut().clear(); + string.make_mut().clear(); } } - pub fn trim(s: &mut ImmutableString) { - let trimmed = s.trim(); + pub fn trim(string: &mut ImmutableString) { + let trimmed = string.trim(); - if trimmed.len() < s.len() { - *s = trimmed.to_string().into(); + if trimmed.len() < string.len() { + *string = trimmed.to_string().into(); } } #[rhai_fn(name = "contains")] - pub fn contains_char(s: &str, ch: char) -> bool { - s.contains(ch) + pub fn contains_char(string: &str, ch: char) -> bool { + string.contains(ch) } - pub fn contains(s: &str, find: ImmutableString) -> bool { - s.contains(find.as_str()) + pub fn contains(string: &str, find_string: &str) -> bool { + string.contains(find_string) } #[rhai_fn(name = "index_of")] - pub fn index_of_char_starting_from(s: &str, ch: char, start: INT) -> INT { + pub fn index_of_char_starting_from(string: &str, ch: char, start: INT) -> INT { let start = if start < 0 { 0 - } else if start as usize >= s.chars().count() { + } else if start as usize >= string.chars().count() { return -1 as INT; } else { - s.chars().take(start as usize).collect::().len() + string + .chars() + .take(start as usize) + .collect::() + .len() }; - s[start..] + string[start..] .find(ch) - .map(|index| s[0..start + index].chars().count() as INT) + .map(|index| string[0..start + index].chars().count() as INT) .unwrap_or(-1 as INT) } #[rhai_fn(name = "index_of")] - pub fn index_of_char(s: &str, ch: char) -> INT { - s.find(ch) - .map(|index| s[0..index].chars().count() as INT) + pub fn index_of_char(string: &str, ch: char) -> INT { + string + .find(ch) + .map(|index| string[0..index].chars().count() as INT) .unwrap_or(-1 as INT) } #[rhai_fn(name = "index_of")] - pub fn index_of_string_starting_from(s: &str, find: ImmutableString, start: INT) -> INT { + pub fn index_of_string_starting_from(string: &str, find_string: &str, start: INT) -> INT { let start = if start < 0 { 0 - } else if start as usize >= s.chars().count() { + } else if start as usize >= string.chars().count() { return -1 as INT; } else { - s.chars().take(start as usize).collect::().len() + string + .chars() + .take(start as usize) + .collect::() + .len() }; - s[start..] - .find(find.as_str()) - .map(|index| s[0..start + index].chars().count() as INT) + string[start..] + .find(find_string) + .map(|index| string[0..start + index].chars().count() as INT) .unwrap_or(-1 as INT) } #[rhai_fn(name = "index_of")] - pub fn index_of(s: &str, find: ImmutableString) -> INT { - s.find(find.as_str()) - .map(|index| s[0..index].chars().count() as INT) + pub fn index_of(string: &str, find_string: &str) -> INT { + string + .find(find_string) + .map(|index| string[0..index].chars().count() as INT) .unwrap_or(-1 as INT) } - pub fn sub_string(s: &str, start: INT, len: INT) -> ImmutableString { - let offset = if s.is_empty() || len <= 0 { + pub fn sub_string(string: &str, start: INT, len: INT) -> ImmutableString { + let offset = if string.is_empty() || len <= 0 { return "".to_string().into(); } else if start < 0 { 0 - } else if start as usize >= s.chars().count() { + } else if start as usize >= string.chars().count() { return "".to_string().into(); } else { start as usize }; - let chars: StaticVec<_> = s.chars().collect(); + let chars: StaticVec<_> = string.chars().collect(); let len = if offset + len as usize > chars.len() { chars.len() - offset @@ -187,26 +199,26 @@ mod string_functions { .into() } #[rhai_fn(name = "sub_string")] - pub fn sub_string_starting_from(s: &str, start: INT) -> ImmutableString { - let len = s.len() as INT; - sub_string(s, start, len) + pub fn sub_string_starting_from(string: &str, start: INT) -> ImmutableString { + let len = string.len() as INT; + sub_string(string, start, len) } #[rhai_fn(name = "crop")] - pub fn crop(s: &mut ImmutableString, start: INT, len: INT) { - let offset = if s.is_empty() || len <= 0 { - s.make_mut().clear(); + pub fn crop(string: &mut ImmutableString, start: INT, len: INT) { + let offset = if string.is_empty() || len <= 0 { + string.make_mut().clear(); return; } else if start < 0 { 0 - } else if start as usize >= s.chars().count() { - s.make_mut().clear(); + } else if start as usize >= string.chars().count() { + string.make_mut().clear(); return; } else { start as usize }; - let chars: StaticVec<_> = s.chars().collect(); + let chars: StaticVec<_> = string.chars().collect(); let len = if offset + len as usize > chars.len() { chars.len() - offset @@ -214,36 +226,50 @@ mod string_functions { len as usize }; - let copy = s.make_mut(); + let copy = string.make_mut(); copy.clear(); copy.extend(chars.iter().skip(offset).take(len)); } #[rhai_fn(name = "crop")] - pub fn crop_string_starting_from(s: &mut ImmutableString, start: INT) { - crop(s, start, s.len() as INT); + pub fn crop_string_starting_from(string: &mut ImmutableString, start: INT) { + crop(string, start, string.len() as INT); } #[rhai_fn(name = "replace")] - pub fn replace(s: &mut ImmutableString, find: ImmutableString, sub: ImmutableString) { - *s = s.replace(find.as_str(), sub.as_str()).into(); + pub fn replace(string: &mut ImmutableString, find_string: &str, substitute_string: &str) { + *string = string.replace(find_string, substitute_string).into(); } #[rhai_fn(name = "replace")] - pub fn replace_string_with_char(s: &mut ImmutableString, find: ImmutableString, sub: char) { - *s = s.replace(find.as_str(), &sub.to_string()).into(); + pub fn replace_string_with_char( + string: &mut ImmutableString, + find_string: &str, + substitute_char: char, + ) { + *string = string + .replace(find_string, &substitute_char.to_string()) + .into(); } #[rhai_fn(name = "replace")] - pub fn replace_char_with_string(s: &mut ImmutableString, find: char, sub: ImmutableString) { - *s = s.replace(&find.to_string(), sub.as_str()).into(); + pub fn replace_char_with_string( + string: &mut ImmutableString, + find_char: char, + substitute_string: &str, + ) { + *string = string + .replace(&find_char.to_string(), substitute_string) + .into(); } #[rhai_fn(name = "replace")] - pub fn replace_char(s: &mut ImmutableString, find: char, sub: char) { - *s = s.replace(&find.to_string(), &sub.to_string()).into(); + pub fn replace_char(string: &mut ImmutableString, find_char: char, substitute_char: char) { + *string = string + .replace(&find_char.to_string(), &substitute_char.to_string()) + .into(); } #[rhai_fn(return_raw)] pub fn pad( _ctx: NativeCallContext, - s: &mut ImmutableString, + string: &mut ImmutableString, len: INT, ch: char, ) -> Result> { @@ -258,17 +284,18 @@ mod string_functions { } if len > 0 { - let orig_len = s.chars().count(); + let orig_len = string.chars().count(); if len as usize > orig_len { - let p = s.make_mut(); + let p = string.make_mut(); for _ in 0..(len as usize - orig_len) { p.push(ch); } #[cfg(not(feature = "unchecked"))] - if _ctx.engine().max_string_size() > 0 && s.len() > _ctx.engine().max_string_size() + if _ctx.engine().max_string_size() > 0 + && string.len() > _ctx.engine().max_string_size() { return crate::EvalAltResult::ErrorDataTooLarge( "Length of string".to_string(), @@ -284,7 +311,7 @@ mod string_functions { #[rhai_fn(name = "pad", return_raw)] pub fn pad_with_string( _ctx: NativeCallContext, - s: &mut ImmutableString, + string: &mut ImmutableString, len: INT, padding: &str, ) -> Result> { @@ -299,11 +326,11 @@ mod string_functions { } if len > 0 { - let mut str_len = s.chars().count(); + let mut str_len = string.chars().count(); let padding_len = padding.chars().count(); if len as usize > str_len { - let p = s.make_mut(); + let p = string.make_mut(); while str_len < len as usize { if str_len + padding_len <= len as usize { @@ -316,7 +343,8 @@ mod string_functions { } #[cfg(not(feature = "unchecked"))] - if _ctx.engine().max_string_size() > 0 && s.len() > _ctx.engine().max_string_size() + if _ctx.engine().max_string_size() > 0 + && string.len() > _ctx.engine().max_string_size() { return crate::EvalAltResult::ErrorDataTooLarge( "Length of string".to_string(), @@ -335,21 +363,19 @@ mod string_functions { use crate::Array; #[rhai_fn(name = "+")] - pub fn append(x: &str, y: Array) -> String { - format!("{}{:?}", x, y) + pub fn append(string: &str, array: Array) -> String { + format!("{}{:?}", string, array) } - #[rhai_fn(name = "+")] - pub fn prepend(x: &mut Array, y: &str) -> String { - format!("{:?}{}", x, y) + #[rhai_fn(name = "+", pure)] + pub fn prepend(array: &mut Array, string: &str) -> String { + format!("{:?}{}", array, string) } - pub fn split(s: &str, delimiter: ImmutableString) -> Array { - s.split(delimiter.as_str()) - .map(Into::::into) - .collect() + pub fn split(string: &str, delimiter: &str) -> Array { + string.split(delimiter).map(Into::::into).collect() } #[rhai_fn(name = "split")] - pub fn split_char(s: &str, delimiter: char) -> Array { - s.split(delimiter).map(Into::::into).collect() + pub fn split_char(string: &str, delimiter: char) -> Array { + string.split(delimiter).map(Into::::into).collect() } } @@ -358,12 +384,12 @@ mod string_functions { use crate::Map; #[rhai_fn(name = "+")] - pub fn append(x: &str, y: Map) -> String { - format!("{}#{:?}", x, y) + pub fn append(string: &str, map: Map) -> String { + format!("{}#{:?}", string, map) } - #[rhai_fn(name = "+")] - pub fn prepend(x: &mut Map, y: &str) -> String { - format!("#{:?}{}", x, y) + #[rhai_fn(name = "+", pure)] + pub fn prepend(map: &mut Map, string: &str) -> String { + format!("#{:?}{}", map, string) } } } diff --git a/src/packages/time_basic.rs b/src/packages/time_basic.rs index cfd49fb9..f8135929 100644 --- a/src/packages/time_basic.rs +++ b/src/packages/time_basic.rs @@ -26,9 +26,9 @@ mod time_functions { } #[rhai_fn(name = "elapsed", get = "elapsed", return_raw)] - pub fn elapsed(timestamp: &mut Instant) -> Result> { + pub fn elapsed(timestamp: Instant) -> Result> { #[cfg(not(feature = "no_float"))] - if *timestamp > Instant::now() { + if timestamp > Instant::now() { Err(make_arithmetic_err("Time-stamp is later than now")) } else { Ok((timestamp.elapsed().as_secs_f64() as FLOAT).into()) @@ -43,7 +43,7 @@ mod time_functions { "Integer overflow for timestamp.elapsed: {}", seconds ))) - } else if *timestamp > Instant::now() { + } else if timestamp > Instant::now() { Err(make_arithmetic_err("Time-stamp is later than now")) } else { Ok((seconds as INT).into()) @@ -52,18 +52,21 @@ mod time_functions { } #[rhai_fn(return_raw, name = "-")] - pub fn time_diff(ts1: Instant, ts2: Instant) -> Result> { + pub fn time_diff( + timestamp: Instant, + timestamp2: Instant, + ) -> Result> { #[cfg(not(feature = "no_float"))] - return Ok(if ts2 > ts1 { - -(ts2 - ts1).as_secs_f64() as FLOAT + return Ok(if timestamp2 > timestamp { + -(timestamp2 - timestamp).as_secs_f64() as FLOAT } else { - (ts1 - ts2).as_secs_f64() as FLOAT + (timestamp - timestamp2).as_secs_f64() as FLOAT } .into()); #[cfg(feature = "no_float")] - if ts2 > ts1 { - let seconds = (ts2 - ts1).as_secs(); + if timestamp2 > timestamp { + let seconds = (timestamp2 - timestamp).as_secs(); if cfg!(not(feature = "unchecked")) && seconds > (MAX_INT as u64) { Err(make_arithmetic_err(format!( @@ -74,7 +77,7 @@ mod time_functions { Ok((-(seconds as INT)).into()) } } else { - let seconds = (ts1 - ts2).as_secs(); + let seconds = (timestamp - timestamp2).as_secs(); if cfg!(not(feature = "unchecked")) && seconds > (MAX_INT as u64) { Err(make_arithmetic_err(format!( @@ -89,9 +92,9 @@ mod time_functions { #[cfg(not(feature = "no_float"))] pub mod float_functions { - fn add_impl(x: Instant, seconds: FLOAT) -> Result> { + fn add_impl(timestamp: Instant, seconds: FLOAT) -> Result> { if seconds < 0.0 { - subtract_impl(x, -seconds) + subtract_impl(timestamp, -seconds) } else if cfg!(not(feature = "unchecked")) { if seconds > (MAX_INT as FLOAT) { Err(make_arithmetic_err(format!( @@ -99,7 +102,8 @@ mod time_functions { seconds ))) } else { - x.checked_add(Duration::from_millis((seconds * 1000.0) as u64)) + timestamp + .checked_add(Duration::from_millis((seconds * 1000.0) as u64)) .ok_or_else(|| { make_arithmetic_err(format!( "Timestamp overflow when adding {} second(s)", @@ -108,12 +112,15 @@ mod time_functions { }) } } else { - Ok(x + Duration::from_millis((seconds * 1000.0) as u64)) + Ok(timestamp + Duration::from_millis((seconds * 1000.0) as u64)) } } - fn subtract_impl(x: Instant, seconds: FLOAT) -> Result> { + fn subtract_impl( + timestamp: Instant, + seconds: FLOAT, + ) -> Result> { if seconds < 0.0 { - add_impl(x, -seconds) + add_impl(timestamp, -seconds) } else if cfg!(not(feature = "unchecked")) { if seconds > (MAX_INT as FLOAT) { Err(make_arithmetic_err(format!( @@ -121,7 +128,8 @@ mod time_functions { seconds ))) } else { - x.checked_sub(Duration::from_millis((seconds * 1000.0) as u64)) + timestamp + .checked_sub(Duration::from_millis((seconds * 1000.0) as u64)) .ok_or_else(|| { make_arithmetic_err(format!( "Timestamp overflow when adding {} second(s)", @@ -130,38 +138,42 @@ mod time_functions { }) } } else { - Ok(x - Duration::from_millis((seconds * 1000.0) as u64)) + Ok(timestamp - Duration::from_millis((seconds * 1000.0) as u64)) } } #[rhai_fn(return_raw, name = "+")] - pub fn add(x: Instant, seconds: FLOAT) -> Result> { - add_impl(x, seconds).map(Into::::into) + pub fn add(timestamp: Instant, seconds: FLOAT) -> Result> { + add_impl(timestamp, seconds).map(Into::::into) } #[rhai_fn(return_raw, name = "+=")] - pub fn add_assign(x: &mut Instant, seconds: FLOAT) -> Result> { - *x = add_impl(*x, seconds)?; + pub fn add_assign( + timestamp: &mut Instant, + seconds: FLOAT, + ) -> Result> { + *timestamp = add_impl(*timestamp, seconds)?; Ok(Dynamic::UNIT) } #[rhai_fn(return_raw, name = "-")] - pub fn subtract(x: Instant, seconds: FLOAT) -> Result> { - subtract_impl(x, seconds).map(Into::::into) + pub fn subtract(timestamp: Instant, seconds: FLOAT) -> Result> { + subtract_impl(timestamp, seconds).map(Into::::into) } #[rhai_fn(return_raw, name = "-=")] pub fn subtract_assign( - x: &mut Instant, + timestamp: &mut Instant, seconds: FLOAT, ) -> Result> { - *x = subtract_impl(*x, seconds)?; + *timestamp = subtract_impl(*timestamp, seconds)?; Ok(Dynamic::UNIT) } } - fn add_impl(x: Instant, seconds: INT) -> Result> { + fn add_impl(timestamp: Instant, seconds: INT) -> Result> { if seconds < 0 { - subtract_impl(x, -seconds) + subtract_impl(timestamp, -seconds) } else if cfg!(not(feature = "unchecked")) { - x.checked_add(Duration::from_secs(seconds as u64)) + timestamp + .checked_add(Duration::from_secs(seconds as u64)) .ok_or_else(|| { make_arithmetic_err(format!( "Timestamp overflow when adding {} second(s)", @@ -169,14 +181,15 @@ mod time_functions { )) }) } else { - Ok(x + Duration::from_secs(seconds as u64)) + Ok(timestamp + Duration::from_secs(seconds as u64)) } } - fn subtract_impl(x: Instant, seconds: INT) -> Result> { + fn subtract_impl(timestamp: Instant, seconds: INT) -> Result> { if seconds < 0 { - add_impl(x, -seconds) + add_impl(timestamp, -seconds) } else if cfg!(not(feature = "unchecked")) { - x.checked_sub(Duration::from_secs(seconds as u64)) + timestamp + .checked_sub(Duration::from_secs(seconds as u64)) .ok_or_else(|| { make_arithmetic_err(format!( "Timestamp overflow when adding {} second(s)", @@ -184,51 +197,57 @@ mod time_functions { )) }) } else { - Ok(x - Duration::from_secs(seconds as u64)) + Ok(timestamp - Duration::from_secs(seconds as u64)) } } #[rhai_fn(return_raw, name = "+")] - pub fn add(x: Instant, seconds: INT) -> Result> { - add_impl(x, seconds).map(Into::::into) + pub fn add(timestamp: Instant, seconds: INT) -> Result> { + add_impl(timestamp, seconds).map(Into::::into) } #[rhai_fn(return_raw, name = "+=")] - pub fn add_assign(x: &mut Instant, seconds: INT) -> Result> { - *x = add_impl(*x, seconds)?; + pub fn add_assign( + timestamp: &mut Instant, + seconds: INT, + ) -> Result> { + *timestamp = add_impl(*timestamp, seconds)?; Ok(Dynamic::UNIT) } #[rhai_fn(return_raw, name = "-")] - pub fn subtract(x: Instant, seconds: INT) -> Result> { - subtract_impl(x, seconds).map(Into::::into) + pub fn subtract(timestamp: Instant, seconds: INT) -> Result> { + subtract_impl(timestamp, seconds).map(Into::::into) } #[rhai_fn(return_raw, name = "-=")] - pub fn subtract_assign(x: &mut Instant, seconds: INT) -> Result> { - *x = subtract_impl(*x, seconds)?; + pub fn subtract_assign( + timestamp: &mut Instant, + seconds: INT, + ) -> Result> { + *timestamp = subtract_impl(*timestamp, seconds)?; Ok(Dynamic::UNIT) } #[rhai_fn(name = "==")] - pub fn eq(x: Instant, y: Instant) -> bool { - x == y + pub fn eq(timestamp: Instant, timestamp2: Instant) -> bool { + timestamp == timestamp2 } #[rhai_fn(name = "!=")] - pub fn ne(x: Instant, y: Instant) -> bool { - x != y + pub fn ne(timestamp: Instant, timestamp2: Instant) -> bool { + timestamp != timestamp2 } #[rhai_fn(name = "<")] - pub fn lt(x: Instant, y: Instant) -> bool { - x < y + pub fn lt(timestamp: Instant, timestamp2: Instant) -> bool { + timestamp < timestamp2 } #[rhai_fn(name = "<=")] - pub fn lte(x: Instant, y: Instant) -> bool { - x <= y + pub fn lte(timestamp: Instant, timestamp2: Instant) -> bool { + timestamp <= timestamp2 } #[rhai_fn(name = ">")] - pub fn gt(x: Instant, y: Instant) -> bool { - x > y + pub fn gt(timestamp: Instant, timestamp2: Instant) -> bool { + timestamp > timestamp2 } #[rhai_fn(name = ">=")] - pub fn gte(x: Instant, y: Instant) -> bool { - x >= y + pub fn gte(timestamp: Instant, timestamp2: Instant) -> bool { + timestamp >= timestamp2 } } diff --git a/src/plugin.rs b/src/plugin.rs index 9882951f..a46afdc4 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -4,7 +4,7 @@ pub use crate::fn_native::{CallableFunction, FnCallArgs}; pub use crate::stdlib::{any::TypeId, boxed::Box, format, mem, string::ToString, vec as new_vec}; pub use crate::{ Dynamic, Engine, EvalAltResult, FnAccess, FnNamespace, ImmutableString, Module, - NativeCallContext, RegisterFn, RegisterResultFn, + NativeCallContext, Position, RegisterFn, RegisterResultFn, }; #[cfg(not(features = "no_module"))] diff --git a/src/result.rs b/src/result.rs index 8fa83ce6..59adae47 100644 --- a/src/result.rs +++ b/src/result.rs @@ -120,7 +120,7 @@ impl EvalAltResult { Self::ErrorVariableNotFound(_, _) => "Variable not found", Self::ErrorModuleNotFound(_, _) => "Module not found", Self::ErrorDataRace(_, _) => "Data race detected when accessing variable", - Self::ErrorAssignmentToConstant(_, _) => "Cannot assign to a constant", + Self::ErrorAssignmentToConstant(_, _) => "Cannot modify a constant", Self::ErrorMismatchOutputType(_, _, _) => "Output type is incorrect", Self::ErrorInExpr(_) => "Malformed 'in' expression", Self::ErrorDotExpr(_, _) => "Malformed dot expression", @@ -196,7 +196,7 @@ impl fmt::Display for EvalAltResult { Self::ErrorRuntime(d, _) if d.is::<()>() => f.write_str(desc)?, Self::ErrorRuntime(d, _) => write!(f, "{}: {}", desc, d)?, - Self::ErrorAssignmentToConstant(s, _) => write!(f, "Cannot assign to constant {}", s)?, + Self::ErrorAssignmentToConstant(s, _) => write!(f, "Cannot modify constant {}", s)?, Self::ErrorMismatchOutputType(s, r, _) => { write!(f, "Output type is incorrect: {} (expecting {})", r, s)? } From 5285dad1a8cd3f18912d8317b35f69c99c65a718 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Fri, 19 Feb 2021 23:48:11 +0800 Subject: [PATCH 6/6] Fix feature build. --- src/packages/iter_basic.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/packages/iter_basic.rs b/src/packages/iter_basic.rs index 4d48ffd8..51eda3dd 100644 --- a/src/packages/iter_basic.rs +++ b/src/packages/iter_basic.rs @@ -42,8 +42,6 @@ where Ok(StepRange::(from, to, step)) } -#[cfg(not(feature = "only_i32"))] -#[cfg(not(feature = "only_i64"))] macro_rules! reg_range { ($lib:expr, $x:expr, $( $y:ty ),*) => ( $( @@ -58,8 +56,6 @@ macro_rules! reg_range { ) } -#[cfg(not(feature = "only_i32"))] -#[cfg(not(feature = "only_i64"))] macro_rules! reg_stepped_range { ($lib:expr, $x:expr, $( $y:ty ),*) => ( $(