Merge pull request #375 from schungx/master
Change HashMap to BTreeMap.
This commit is contained in:
commit
77a71dbbf0
17
CHANGELOG.md
17
CHANGELOG.md
@ -4,18 +4,33 @@ Rhai Release Notes
|
|||||||
Version 0.19.15
|
Version 0.19.15
|
||||||
===============
|
===============
|
||||||
|
|
||||||
|
This version replaces internal usage of `HashMap` with `BTreeMap` in many cases, which should result
|
||||||
|
in speed improvements because a `BTreeMap` is faster when the number of items held is small.
|
||||||
|
|
||||||
|
This also translates to the Rhai object map type, `Map`, which used to be an alias to `HashMap` and
|
||||||
|
is now aliased to `BTreeMap` instead. This change is due to the fact that, in the vast majority of
|
||||||
|
object map usages, the number of properties held is small.
|
||||||
|
|
||||||
|
`HashMap` and `BTreeMap` have almost identical public API's so this change is unlikely to break a
|
||||||
|
lot of existing code.
|
||||||
|
|
||||||
|
|
||||||
Breaking changes
|
Breaking changes
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
|
* `Map` is now an alias to `BTreeMap` instead of `HashMap`. This is because most object maps used have few properties.
|
||||||
* The traits `RegisterFn` and `RegisterResultFn` are removed. `Engine::register_fn` and `Engine::register_result_fn` are now implemented directly on `Engine`.
|
* The traits `RegisterFn` and `RegisterResultFn` are removed. `Engine::register_fn` and `Engine::register_result_fn` are now implemented directly on `Engine`.
|
||||||
* `FnPtr::call_dynamic` now takes `&NativeCallContext` instead of consuming it.
|
* `FnPtr::call_dynamic` now takes `&NativeCallContext` instead of consuming it.
|
||||||
* All `Module::set_fn_XXX` methods are removed, in favor of `Module::set_native_fn`.
|
* All `Module::set_fn_XXX` methods are removed, in favor of `Module::set_native_fn`.
|
||||||
|
* `Array::reduce` and `Array::reduce_rev` now take a `Dynamic` as initial value instead of a function pointer.
|
||||||
* `protected`, `super` are now reserved keywords.
|
* `protected`, `super` are now reserved keywords.
|
||||||
|
|
||||||
Enhancements
|
Enhancements
|
||||||
------------
|
------------
|
||||||
|
|
||||||
* `Engine::register_result_fn` no longer requires the successful return type to be `Dynamic`. It can now be any type.
|
* Replaced most `HashMap` usage with `BTreeMap` for better performance when the number of items is small.
|
||||||
|
* `Engine::register_result_fn` no longer requires the successful return type to be `Dynamic`. It can now be any clonable type.
|
||||||
|
* `#[rhai_fn(return_raw)]` can now return `Result<T, Box<EvalAltResult>>` where `T` is any clonable type instead of `Result<Dynamic, Box<EvalAltResult>>`.
|
||||||
|
|
||||||
|
|
||||||
Version 0.19.14
|
Version 0.19.14
|
||||||
|
15
Cargo.toml
15
Cargo.toml
@ -17,9 +17,9 @@ categories = ["no-std", "embedded", "wasm", "parser-implementations"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
smallvec = { version = "1.6", default-features = false, features = ["union"] }
|
smallvec = { version = "1.6", default-features = false, features = ["union"] }
|
||||||
ahash = { version = "0.6", default-features = false }
|
ahash = { version = "0.7", default-features = false }
|
||||||
num-traits = { version = "0.2", default_features = false }
|
num-traits = { version = "0.2", default_features = false }
|
||||||
rhai_codegen = { version = "0.3.3", path = "codegen" }
|
rhai_codegen = { version = "0.3.4", path = "codegen" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
@ -40,8 +40,7 @@ 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
|
metadata = ["serde", "serde_json"] # enables exporting functions metadata to JSON
|
||||||
|
|
||||||
# compiling for no-std
|
no_std = ["smallvec/union", "num-traits/libm", "core-error", "libm", "ahash/compile-time-rng"]
|
||||||
no_std = ["smallvec/union", "num-traits/libm", "hashbrown", "core-error", "libm", "ahash/compile-time-rng"]
|
|
||||||
|
|
||||||
# compiling for WASM
|
# compiling for WASM
|
||||||
wasm-bindgen = ["instant/wasm-bindgen"]
|
wasm-bindgen = ["instant/wasm-bindgen"]
|
||||||
@ -64,12 +63,6 @@ default_features = false
|
|||||||
features = ["alloc"]
|
features = ["alloc"]
|
||||||
optional = true
|
optional = true
|
||||||
|
|
||||||
[dependencies.hashbrown]
|
|
||||||
version = "0.7"
|
|
||||||
default-features = false
|
|
||||||
features = ["ahash", "nightly", "inline-more"]
|
|
||||||
optional = true
|
|
||||||
|
|
||||||
[dependencies.serde]
|
[dependencies.serde]
|
||||||
version = "1.0"
|
version = "1.0"
|
||||||
default_features = false
|
default_features = false
|
||||||
@ -99,4 +92,4 @@ instant = { version = "0.1" } # WASM implementation of std::time::Instant
|
|||||||
instant = { version = "0.1" } # WASM implementation of std::time::Instant
|
instant = { version = "0.1" } # WASM implementation of std::time::Instant
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
features = ["metadata", "internals", "decimal"]
|
features = ["metadata", "internals", "decimal"] # compiling for no-std
|
||||||
|
17
README.md
17
README.md
@ -28,11 +28,11 @@ Supported targets and builds
|
|||||||
Standard features
|
Standard features
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
* Simple language similar to JavaScript+Rust with dynamic typing.
|
* Simple language similar to JavaScript+Rust with [dynamic](https://rhai.rs/book/language/dynamic.html) typing.
|
||||||
* Fairly efficient evaluation (1 million iterations in 0.3 sec on a single-core, 2.3 GHz Linux VM).
|
* 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).
|
* 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.
|
* Freely pass Rust values into a script as [variables](https://rhai.rs/book/language/variables.html)/[constants](https://rhai.rs/book/language/constants.html) via an external [`Scope`](https://rhai.rs/book/rust/scope.html) - all clonable Rust types are supported; no need to implement any special trait. Or tap directly into the [variable resolution process](https://rhai.rs/book/engine/var.html).
|
||||||
* 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.
|
* Built-in support for most common [data types](https://rhai.rs/book/language/values-and-types.html) including booleans, [integers](https://rhai.rs/book/language/numbers.html), [floating-point numbers](https://rhai.rs/book/language/numbers.html) (including [`Decimal`](https://crates.io/crates/rust_decimal)), [strings](https://rhai.rs/book/language/strings-chars.html), [Unicode characters](https://rhai.rs/book/language/strings-chars.html), [arrays](https://rhai.rs/book/language/arrays.html) and [object maps](https://rhai.rs/book/language/object-maps.html).
|
||||||
* Easily [call a script-defined function](https://rhai.rs/book/engine/call-fn.html) from Rust.
|
* 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).
|
* Relatively little `unsafe` code (yes there are some for performance reasons).
|
||||||
* Few dependencies (currently only [`smallvec`](https://crates.io/crates/smallvec), [`num-traits`](https://crates.io/crates/num-traits) and [`ahash`](https://crates.io/crates/ahash)).
|
* Few dependencies (currently only [`smallvec`](https://crates.io/crates/smallvec), [`num-traits`](https://crates.io/crates/num-traits) and [`ahash`](https://crates.io/crates/ahash)).
|
||||||
@ -44,7 +44,7 @@ Standard features
|
|||||||
* Dynamic dispatch via [function pointers](https://rhai.rs/book/language/fn-ptr.html) with additional support for [currying](https://rhai.rs/book/language/fn-curry.html).
|
* Dynamic dispatch via [function pointers](https://rhai.rs/book/language/fn-ptr.html) with additional support for [currying](https://rhai.rs/book/language/fn-curry.html).
|
||||||
* [Closures](https://rhai.rs/book/language/fn-closure.html) (anonymous functions) that can capture shared values.
|
* [Closures](https://rhai.rs/book/language/fn-closure.html) (anonymous functions) that can capture shared values.
|
||||||
* Some syntactic support for [object-oriented programming (OOP)](https://rhai.rs/book/language/oop.html).
|
* Some syntactic support for [object-oriented programming (OOP)](https://rhai.rs/book/language/oop.html).
|
||||||
* Organize code base with dynamically-loadable [modules](https://rhai.rs/book/language/modules.html), optionally overriding the resolution process
|
* Organize code base with dynamically-loadable [modules](https://rhai.rs/book/language/modules.html), optionally [overriding the resolution process](https://rhai.rs/book/rust/modules/resolvers.html).
|
||||||
* Serialization/deserialization support via [serde](https://crates.io/crates/serde) (requires the `serde` feature).
|
* Serialization/deserialization support via [serde](https://crates.io/crates/serde) (requires the `serde` feature).
|
||||||
* Support for [minimal builds](https://rhai.rs/book/start/builds/minimal.html) by excluding unneeded language [features](https://rhai.rs/book/start/features.html).
|
* Support for [minimal builds](https://rhai.rs/book/start/builds/minimal.html) by excluding unneeded language [features](https://rhai.rs/book/start/features.html).
|
||||||
|
|
||||||
@ -52,7 +52,8 @@ Standard features
|
|||||||
Protected against attacks
|
Protected against attacks
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
* Sand-boxed - the scripting engine, if declared immutable, cannot mutate the containing environment unless [explicitly permitted](https://rhai.rs/book/patterns/control.html).
|
* _Don't Panic_ guarantee - Any panic is a bug. Rhai subscribes to the motto that a library should never panic the host system, and is coded with this in mind.
|
||||||
|
* [Sand-boxed](https://rhai.rs/book/safety/sandbox.html) - the scripting engine, if declared immutable, cannot mutate the containing environment unless [explicitly permitted](https://rhai.rs/book/patterns/control.html).
|
||||||
* Rugged - protected against malicious attacks (such as [stack-overflow](https://rhai.rs/book/safety/max-call-stack.html), [over-sized data](https://rhai.rs/book/safety/max-string-size.html), and [runaway scripts](https://rhai.rs/book/safety/max-operations.html) etc.) that may come from untrusted third-party user-land scripts.
|
* Rugged - protected against malicious attacks (such as [stack-overflow](https://rhai.rs/book/safety/max-call-stack.html), [over-sized data](https://rhai.rs/book/safety/max-string-size.html), and [runaway scripts](https://rhai.rs/book/safety/max-operations.html) etc.) that may come from untrusted third-party user-land scripts.
|
||||||
* Track script evaluation [progress](https://rhai.rs/book/safety/progress.html) and manually terminate a script run.
|
* Track script evaluation [progress](https://rhai.rs/book/safety/progress.html) and manually terminate a script run.
|
||||||
|
|
||||||
@ -75,14 +76,14 @@ Project Site
|
|||||||
Documentation
|
Documentation
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
See [The Rhai Book](https://rhai.rs/book) for details on the Rhai scripting engine and language.
|
See [_The Rhai Book_](https://rhai.rs/book) for details on the Rhai scripting engine and language.
|
||||||
|
|
||||||
|
|
||||||
Playground
|
Playground
|
||||||
----------
|
----------
|
||||||
|
|
||||||
An [Online Playground](https://rhai.rs/playground) is available with
|
An [_Online Playground_](https://rhai.rs/playground) is available with syntax-highlighting editor,
|
||||||
syntax-highlighting editor, powered by WebAssembly.
|
powered by WebAssembly.
|
||||||
|
|
||||||
Scripts can be evaluated directly from the editor.
|
Scripts can be evaluated directly from the editor.
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "rhai_codegen"
|
name = "rhai_codegen"
|
||||||
version = "0.3.3"
|
version = "0.3.4"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
authors = ["jhwgh1968"]
|
authors = ["jhwgh1968"]
|
||||||
description = "Procedural macro support package for Rhai, a scripting language for Rust"
|
description = "Procedural macro support package for Rhai, a scripting language for Rust"
|
||||||
@ -12,7 +12,7 @@ license = "MIT OR Apache-2.0"
|
|||||||
proc-macro = true
|
proc-macro = true
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
rhai = { path = ".." }
|
rhai = { path = "..", version = "^0.19.15" }
|
||||||
trybuild = "1"
|
trybuild = "1"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
@ -279,7 +279,6 @@ pub struct ExportedFn {
|
|||||||
signature: syn::Signature,
|
signature: syn::Signature,
|
||||||
visibility: syn::Visibility,
|
visibility: syn::Visibility,
|
||||||
pass_context: bool,
|
pass_context: bool,
|
||||||
return_dynamic: bool,
|
|
||||||
mut_receiver: bool,
|
mut_receiver: bool,
|
||||||
params: ExportedFnParams,
|
params: ExportedFnParams,
|
||||||
}
|
}
|
||||||
@ -290,10 +289,6 @@ impl Parse for ExportedFn {
|
|||||||
let entire_span = fn_all.span();
|
let entire_span = fn_all.span();
|
||||||
let str_type_path = syn::parse2::<syn::Path>(quote! { str }).unwrap();
|
let str_type_path = syn::parse2::<syn::Path>(quote! { str }).unwrap();
|
||||||
|
|
||||||
let dynamic_type_path1 = syn::parse2::<syn::Path>(quote! { Dynamic }).unwrap();
|
|
||||||
let dynamic_type_path2 = syn::parse2::<syn::Path>(quote! { rhai::Dynamic }).unwrap();
|
|
||||||
let mut return_dynamic = false;
|
|
||||||
|
|
||||||
let context_type_path1 = syn::parse2::<syn::Path>(quote! { NativeCallContext }).unwrap();
|
let context_type_path1 = syn::parse2::<syn::Path>(quote! { NativeCallContext }).unwrap();
|
||||||
let context_type_path2 =
|
let context_type_path2 =
|
||||||
syn::parse2::<syn::Path>(quote! { rhai::NativeCallContext }).unwrap();
|
syn::parse2::<syn::Path>(quote! { rhai::NativeCallContext }).unwrap();
|
||||||
@ -400,11 +395,6 @@ impl Parse for ExportedFn {
|
|||||||
"Rhai functions cannot return references",
|
"Rhai functions cannot return references",
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
syn::Type::Path(p)
|
|
||||||
if p.path == dynamic_type_path1 || p.path == dynamic_type_path2 =>
|
|
||||||
{
|
|
||||||
return_dynamic = true
|
|
||||||
}
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -413,7 +403,6 @@ impl Parse for ExportedFn {
|
|||||||
signature: fn_all.sig,
|
signature: fn_all.sig,
|
||||||
visibility,
|
visibility,
|
||||||
pass_context,
|
pass_context,
|
||||||
return_dynamic,
|
|
||||||
mut_receiver,
|
mut_receiver,
|
||||||
params: Default::default(),
|
params: Default::default(),
|
||||||
})
|
})
|
||||||
@ -520,7 +509,7 @@ impl ExportedFn {
|
|||||||
if params.return_raw.is_some() && self.return_type().is_none() {
|
if params.return_raw.is_some() && self.return_type().is_none() {
|
||||||
return Err(syn::Error::new(
|
return Err(syn::Error::new(
|
||||||
params.return_raw.unwrap(),
|
params.return_raw.unwrap(),
|
||||||
"functions marked with 'return_raw' must return Result<Dynamic, Box<EvalAltResult>>",
|
"functions marked with 'return_raw' must return Result<T, Box<EvalAltResult>>",
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -602,9 +591,8 @@ impl ExportedFn {
|
|||||||
syn::Ident::new(&format!("rhai_fn_{}", self.name()), self.name().span());
|
syn::Ident::new(&format!("rhai_fn_{}", self.name()), self.name().span());
|
||||||
let impl_block = self.generate_impl("Token");
|
let impl_block = self.generate_impl("Token");
|
||||||
let callable_block = self.generate_callable("Token");
|
let callable_block = self.generate_callable("Token");
|
||||||
let input_names_block = self.generate_input_names("Token");
|
let param_names_block = self.generate_param_names("Token");
|
||||||
let input_types_block = self.generate_input_types("Token");
|
let input_types_block = self.generate_input_types("Token");
|
||||||
let return_type_block = self.generate_return_type("Token");
|
|
||||||
let dyn_result_fn_block = self.generate_dynamic_fn();
|
let dyn_result_fn_block = self.generate_dynamic_fn();
|
||||||
let vis = self.visibility;
|
let vis = self.visibility;
|
||||||
quote! {
|
quote! {
|
||||||
@ -614,10 +602,8 @@ impl ExportedFn {
|
|||||||
struct Token();
|
struct Token();
|
||||||
#impl_block
|
#impl_block
|
||||||
#callable_block
|
#callable_block
|
||||||
#input_names_block
|
#param_names_block
|
||||||
#input_types_block
|
#input_types_block
|
||||||
#return_type_block
|
|
||||||
#[allow(unused)]
|
|
||||||
#dyn_result_fn_block
|
#dyn_result_fn_block
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -656,17 +642,13 @@ impl ExportedFn {
|
|||||||
if self.params.return_raw.is_some() {
|
if self.params.return_raw.is_some() {
|
||||||
quote_spanned! { return_span =>
|
quote_spanned! { return_span =>
|
||||||
pub #dynamic_signature {
|
pub #dynamic_signature {
|
||||||
#name(#(#arguments),*)
|
#name(#(#arguments),*).map(Dynamic::from)
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if self.return_dynamic {
|
|
||||||
quote_spanned! { return_span =>
|
|
||||||
pub #dynamic_signature {
|
|
||||||
Ok(#name(#(#arguments),*))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
quote_spanned! { return_span =>
|
quote_spanned! { return_span =>
|
||||||
|
#[allow(unused)]
|
||||||
|
#[inline(always)]
|
||||||
pub #dynamic_signature {
|
pub #dynamic_signature {
|
||||||
Ok(Dynamic::from(#name(#(#arguments),*)))
|
Ok(Dynamic::from(#name(#(#arguments),*)))
|
||||||
}
|
}
|
||||||
@ -681,21 +663,23 @@ impl ExportedFn {
|
|||||||
self.name().span(),
|
self.name().span(),
|
||||||
);
|
);
|
||||||
quote! {
|
quote! {
|
||||||
|
#[inline(always)]
|
||||||
pub fn #callable_fn_name() -> CallableFunction {
|
pub fn #callable_fn_name() -> CallableFunction {
|
||||||
#token_name().into()
|
#token_name().into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_input_names(&self, on_type_name: &str) -> proc_macro2::TokenStream {
|
pub fn generate_param_names(&self, on_type_name: &str) -> proc_macro2::TokenStream {
|
||||||
let token_name: syn::Ident = syn::Ident::new(on_type_name, self.name().span());
|
let token_name: syn::Ident = syn::Ident::new(on_type_name, self.name().span());
|
||||||
let input_names_fn_name: syn::Ident = syn::Ident::new(
|
let param_names_fn_name: syn::Ident = syn::Ident::new(
|
||||||
&format!("{}_input_names", on_type_name.to_lowercase()),
|
&format!("{}_param_names", on_type_name.to_lowercase()),
|
||||||
self.name().span(),
|
self.name().span(),
|
||||||
);
|
);
|
||||||
quote! {
|
quote! {
|
||||||
pub fn #input_names_fn_name() -> Box<[&'static str]> {
|
#[inline(always)]
|
||||||
#token_name().input_names()
|
pub fn #param_names_fn_name() -> Box<[&'static str]> {
|
||||||
|
#token_name().param_names()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -707,25 +691,13 @@ impl ExportedFn {
|
|||||||
self.name().span(),
|
self.name().span(),
|
||||||
);
|
);
|
||||||
quote! {
|
quote! {
|
||||||
|
#[inline(always)]
|
||||||
pub fn #input_types_fn_name() -> Box<[TypeId]> {
|
pub fn #input_types_fn_name() -> Box<[TypeId]> {
|
||||||
#token_name().input_types()
|
#token_name().input_types()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_return_type(&self, on_type_name: &str) -> proc_macro2::TokenStream {
|
|
||||||
let token_name: syn::Ident = syn::Ident::new(on_type_name, self.name().span());
|
|
||||||
let return_type_fn_name: syn::Ident = syn::Ident::new(
|
|
||||||
&format!("{}_return_type", on_type_name.to_lowercase()),
|
|
||||||
self.name().span(),
|
|
||||||
);
|
|
||||||
quote! {
|
|
||||||
pub fn #return_type_fn_name() -> &'static str {
|
|
||||||
#token_name().return_type()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn generate_impl(&self, on_type_name: &str) -> proc_macro2::TokenStream {
|
pub fn generate_impl(&self, on_type_name: &str) -> proc_macro2::TokenStream {
|
||||||
let sig_name = self.name().clone();
|
let sig_name = self.name().clone();
|
||||||
let arg_count = self.arg_count();
|
let arg_count = self.arg_count();
|
||||||
@ -890,42 +862,34 @@ impl ExportedFn {
|
|||||||
.map(|r| r.span())
|
.map(|r| r.span())
|
||||||
.unwrap_or_else(|| proc_macro2::Span::call_site());
|
.unwrap_or_else(|| proc_macro2::Span::call_site());
|
||||||
let return_expr = if !self.params.return_raw.is_some() {
|
let return_expr = if !self.params.return_raw.is_some() {
|
||||||
if self.return_dynamic {
|
|
||||||
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),*)))
|
Ok(Dynamic::from(#sig_name(#(#unpack_exprs),*)))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
quote_spanned! { return_span =>
|
quote_spanned! { return_span =>
|
||||||
#sig_name(#(#unpack_exprs),*)
|
#sig_name(#(#unpack_exprs),*).map(Dynamic::from)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let type_name = syn::Ident::new(on_type_name, proc_macro2::Span::call_site());
|
let type_name = syn::Ident::new(on_type_name, proc_macro2::Span::call_site());
|
||||||
quote! {
|
quote! {
|
||||||
impl PluginFunction for #type_name {
|
impl PluginFunction for #type_name {
|
||||||
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result<Dynamic, Box<EvalAltResult>> {
|
#[inline(always)]
|
||||||
|
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
|
||||||
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)*
|
#(#unpack_statements)*
|
||||||
#return_expr
|
#return_expr
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_method_call(&self) -> bool { #is_method_call }
|
#[inline(always)] fn is_method_call(&self) -> bool { #is_method_call }
|
||||||
fn is_variadic(&self) -> bool { false }
|
#[inline(always)] fn is_variadic(&self) -> bool { false }
|
||||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> { Box::new(#type_name()) }
|
#[inline(always)] fn clone_boxed(&self) -> Box<dyn PluginFunction> { Box::new(#type_name()) }
|
||||||
fn input_names(&self) -> Box<[&'static str]> {
|
#[inline(always)] fn param_names(&self) -> Box<[&'static str]> {
|
||||||
new_vec![#(#input_type_names),*].into_boxed_slice()
|
new_vec![#(#input_type_names,)* #return_type].into_boxed_slice()
|
||||||
}
|
}
|
||||||
fn input_types(&self) -> Box<[TypeId]> {
|
#[inline(always)] fn input_types(&self) -> Box<[TypeId]> {
|
||||||
new_vec![#(#input_type_exprs),*].into_boxed_slice()
|
new_vec![#(#input_type_exprs),*].into_boxed_slice()
|
||||||
}
|
}
|
||||||
fn return_type(&self) -> &'static str {
|
|
||||||
#return_type
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -340,7 +340,7 @@ pub fn set_exported_fn(args: proc_macro::TokenStream) -> proc_macro::TokenStream
|
|||||||
let gen_mod_path = crate::register::generated_module_path(&rust_mod_path);
|
let gen_mod_path = crate::register::generated_module_path(&rust_mod_path);
|
||||||
let tokens = quote! {
|
let tokens = quote! {
|
||||||
#module_expr.set_fn(#export_name, FnNamespace::Internal, FnAccess::Public,
|
#module_expr.set_fn(#export_name, FnNamespace::Internal, FnAccess::Public,
|
||||||
Some(#gen_mod_path::token_input_names().as_ref()),
|
Some(#gen_mod_path::token_param_names().as_ref()),
|
||||||
#gen_mod_path::token_input_types().as_ref(),
|
#gen_mod_path::token_input_types().as_ref(),
|
||||||
#gen_mod_path::token_callable());
|
#gen_mod_path::token_callable());
|
||||||
};
|
};
|
||||||
@ -382,7 +382,7 @@ pub fn set_exported_global_fn(args: proc_macro::TokenStream) -> proc_macro::Toke
|
|||||||
let gen_mod_path = crate::register::generated_module_path(&rust_mod_path);
|
let gen_mod_path = crate::register::generated_module_path(&rust_mod_path);
|
||||||
let tokens = quote! {
|
let tokens = quote! {
|
||||||
#module_expr.set_fn(#export_name, FnNamespace::Global, FnAccess::Public,
|
#module_expr.set_fn(#export_name, FnNamespace::Global, FnAccess::Public,
|
||||||
Some(#gen_mod_path::token_input_names().as_ref()),
|
Some(#gen_mod_path::token_param_names().as_ref()),
|
||||||
#gen_mod_path::token_input_types().as_ref(),
|
#gen_mod_path::token_input_types().as_ref(),
|
||||||
#gen_mod_path::token_callable());
|
#gen_mod_path::token_callable());
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use quote::{quote, ToTokens};
|
use quote::{quote, ToTokens};
|
||||||
|
|
||||||
@ -185,9 +185,8 @@ pub fn generate_body(
|
|||||||
});
|
});
|
||||||
gen_fn_tokens.push(function.generate_impl(&fn_token_name.to_string()));
|
gen_fn_tokens.push(function.generate_impl(&fn_token_name.to_string()));
|
||||||
gen_fn_tokens.push(function.generate_callable(&fn_token_name.to_string()));
|
gen_fn_tokens.push(function.generate_callable(&fn_token_name.to_string()));
|
||||||
gen_fn_tokens.push(function.generate_input_names(&fn_token_name.to_string()));
|
gen_fn_tokens.push(function.generate_param_names(&fn_token_name.to_string()));
|
||||||
gen_fn_tokens.push(function.generate_input_types(&fn_token_name.to_string()));
|
gen_fn_tokens.push(function.generate_input_types(&fn_token_name.to_string()));
|
||||||
gen_fn_tokens.push(function.generate_return_type(&fn_token_name.to_string()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut generate_fn_call = syn::parse2::<syn::ItemMod>(quote! {
|
let mut generate_fn_call = syn::parse2::<syn::ItemMod>(quote! {
|
||||||
@ -239,8 +238,8 @@ pub fn check_rename_collisions(fns: &Vec<ExportedFn>) -> Result<(), syn::Error>
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut renames = HashMap::<String, proc_macro2::Span>::new();
|
let mut renames = BTreeMap::<String, proc_macro2::Span>::new();
|
||||||
let mut fn_defs = HashMap::<String, proc_macro2::Span>::new();
|
let mut fn_defs = BTreeMap::<String, proc_macro2::Span>::new();
|
||||||
|
|
||||||
for item_fn in fns.iter() {
|
for item_fn in fns.iter() {
|
||||||
if !item_fn.params().name.is_empty() || item_fn.params().special != FnSpecialAccess::None {
|
if !item_fn.params().name.is_empty() || item_fn.params().special != FnSpecialAccess::None {
|
||||||
|
@ -277,39 +277,33 @@ mod generate_tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
struct Token();
|
struct Token();
|
||||||
impl PluginFunction for Token {
|
impl PluginFunction for Token {
|
||||||
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result<Dynamic, Box<EvalAltResult>> {
|
#[inline(always)] fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
|
||||||
debug_assert_eq!(args.len(), 0usize,
|
debug_assert_eq!(args.len(), 0usize,
|
||||||
"wrong arg count: {} != {}", args.len(), 0usize);
|
"wrong arg count: {} != {}", args.len(), 0usize);
|
||||||
Ok(Dynamic::from(do_nothing()))
|
Ok(Dynamic::from(do_nothing()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_method_call(&self) -> bool { false }
|
#[inline(always)] fn is_method_call(&self) -> bool { false }
|
||||||
fn is_variadic(&self) -> bool { false }
|
#[inline(always)] fn is_variadic(&self) -> bool { false }
|
||||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> { Box::new(Token()) }
|
#[inline(always)] fn clone_boxed(&self) -> Box<dyn PluginFunction> { Box::new(Token()) }
|
||||||
fn input_names(&self) -> Box<[&'static str]> {
|
#[inline(always)] fn param_names(&self) -> Box<[&'static str]> {
|
||||||
|
new_vec!["()"].into_boxed_slice()
|
||||||
|
}
|
||||||
|
#[inline(always)] fn input_types(&self) -> Box<[TypeId]> {
|
||||||
new_vec![].into_boxed_slice()
|
new_vec![].into_boxed_slice()
|
||||||
}
|
}
|
||||||
fn input_types(&self) -> Box<[TypeId]> {
|
|
||||||
new_vec![].into_boxed_slice()
|
|
||||||
}
|
}
|
||||||
fn return_type(&self) -> &'static str {
|
#[inline(always)] pub fn token_callable() -> CallableFunction {
|
||||||
"()"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn token_callable() -> CallableFunction {
|
|
||||||
Token().into()
|
Token().into()
|
||||||
}
|
}
|
||||||
pub fn token_input_names() -> Box<[&'static str]> {
|
#[inline(always)] pub fn token_param_names() -> Box<[&'static str]> {
|
||||||
Token().input_names()
|
Token().param_names()
|
||||||
}
|
}
|
||||||
pub fn token_input_types() -> Box<[TypeId]> {
|
#[inline(always)] pub fn token_input_types() -> Box<[TypeId]> {
|
||||||
Token().input_types()
|
Token().input_types()
|
||||||
}
|
}
|
||||||
pub fn token_return_type() -> &'static str {
|
|
||||||
Token().return_type()
|
|
||||||
}
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub fn dynamic_result_fn() -> Result<Dynamic, Box<EvalAltResult> > {
|
#[inline(always)] pub fn dynamic_result_fn() -> Result<Dynamic, Box<EvalAltResult> > {
|
||||||
Ok(Dynamic::from(do_nothing()))
|
Ok(Dynamic::from(do_nothing()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -331,40 +325,35 @@ mod generate_tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
struct Token();
|
struct Token();
|
||||||
impl PluginFunction for Token {
|
impl PluginFunction for Token {
|
||||||
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result<Dynamic, Box<EvalAltResult>> {
|
#[inline(always)]
|
||||||
|
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
|
||||||
debug_assert_eq!(args.len(), 1usize,
|
debug_assert_eq!(args.len(), 1usize,
|
||||||
"wrong arg count: {} != {}", args.len(), 1usize);
|
"wrong arg count: {} != {}", args.len(), 1usize);
|
||||||
let arg0 = mem::take(args[0usize]).cast::<usize>();
|
let arg0 = mem::take(args[0usize]).cast::<usize>();
|
||||||
Ok(Dynamic::from(do_something(arg0)))
|
Ok(Dynamic::from(do_something(arg0)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_method_call(&self) -> bool { false }
|
#[inline(always)] fn is_method_call(&self) -> bool { false }
|
||||||
fn is_variadic(&self) -> bool { false }
|
#[inline(always)] fn is_variadic(&self) -> bool { false }
|
||||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> { Box::new(Token()) }
|
#[inline(always)] fn clone_boxed(&self) -> Box<dyn PluginFunction> { Box::new(Token()) }
|
||||||
fn input_names(&self) -> Box<[&'static str]> {
|
#[inline(always)] fn param_names(&self) -> Box<[&'static str]> {
|
||||||
new_vec!["x: usize"].into_boxed_slice()
|
new_vec!["x: usize", "()"].into_boxed_slice()
|
||||||
}
|
}
|
||||||
fn input_types(&self) -> Box<[TypeId]> {
|
#[inline(always)] fn input_types(&self) -> Box<[TypeId]> {
|
||||||
new_vec![TypeId::of::<usize>()].into_boxed_slice()
|
new_vec![TypeId::of::<usize>()].into_boxed_slice()
|
||||||
}
|
}
|
||||||
fn return_type(&self) -> &'static str {
|
|
||||||
"()"
|
|
||||||
}
|
}
|
||||||
}
|
#[inline(always)] pub fn token_callable() -> CallableFunction {
|
||||||
pub fn token_callable() -> CallableFunction {
|
|
||||||
Token().into()
|
Token().into()
|
||||||
}
|
}
|
||||||
pub fn token_input_names() -> Box<[&'static str]> {
|
#[inline(always)] pub fn token_param_names() -> Box<[&'static str]> {
|
||||||
Token().input_names()
|
Token().param_names()
|
||||||
}
|
}
|
||||||
pub fn token_input_types() -> Box<[TypeId]> {
|
#[inline(always)] pub fn token_input_types() -> Box<[TypeId]> {
|
||||||
Token().input_types()
|
Token().input_types()
|
||||||
}
|
}
|
||||||
pub fn token_return_type() -> &'static str {
|
|
||||||
Token().return_type()
|
|
||||||
}
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub fn dynamic_result_fn(x: usize) -> Result<Dynamic, Box<EvalAltResult> > {
|
#[inline(always)] pub fn dynamic_result_fn(x: usize) -> Result<Dynamic, Box<EvalAltResult> > {
|
||||||
Ok(Dynamic::from(do_something(x)))
|
Ok(Dynamic::from(do_something(x)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -386,40 +375,35 @@ mod generate_tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
struct Token();
|
struct Token();
|
||||||
impl PluginFunction for Token {
|
impl PluginFunction for Token {
|
||||||
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result<Dynamic, Box<EvalAltResult>> {
|
#[inline(always)]
|
||||||
|
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
|
||||||
debug_assert_eq!(args.len(), 1usize,
|
debug_assert_eq!(args.len(), 1usize,
|
||||||
"wrong arg count: {} != {}", args.len(), 1usize);
|
"wrong arg count: {} != {}", args.len(), 1usize);
|
||||||
let arg0 = mem::take(args[0usize]).cast::<usize>();
|
let arg0 = mem::take(args[0usize]).cast::<usize>();
|
||||||
Ok(Dynamic::from(do_something(context, arg0)))
|
Ok(Dynamic::from(do_something(context, arg0)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_method_call(&self) -> bool { false }
|
#[inline(always)] fn is_method_call(&self) -> bool { false }
|
||||||
fn is_variadic(&self) -> bool { false }
|
#[inline(always)] fn is_variadic(&self) -> bool { false }
|
||||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> { Box::new(Token()) }
|
#[inline(always)] fn clone_boxed(&self) -> Box<dyn PluginFunction> { Box::new(Token()) }
|
||||||
fn input_names(&self) -> Box<[&'static str]> {
|
#[inline(always)] fn param_names(&self) -> Box<[&'static str]> {
|
||||||
new_vec!["x: usize"].into_boxed_slice()
|
new_vec!["x: usize", "()"].into_boxed_slice()
|
||||||
}
|
}
|
||||||
fn input_types(&self) -> Box<[TypeId]> {
|
#[inline(always)] fn input_types(&self) -> Box<[TypeId]> {
|
||||||
new_vec![TypeId::of::<usize>()].into_boxed_slice()
|
new_vec![TypeId::of::<usize>()].into_boxed_slice()
|
||||||
}
|
}
|
||||||
fn return_type(&self) -> &'static str {
|
|
||||||
"()"
|
|
||||||
}
|
}
|
||||||
}
|
#[inline(always)] pub fn token_callable() -> CallableFunction {
|
||||||
pub fn token_callable() -> CallableFunction {
|
|
||||||
Token().into()
|
Token().into()
|
||||||
}
|
}
|
||||||
pub fn token_input_names() -> Box<[&'static str]> {
|
#[inline(always)] pub fn token_param_names() -> Box<[&'static str]> {
|
||||||
Token().input_names()
|
Token().param_names()
|
||||||
}
|
}
|
||||||
pub fn token_input_types() -> Box<[TypeId]> {
|
#[inline(always)] pub fn token_input_types() -> Box<[TypeId]> {
|
||||||
Token().input_types()
|
Token().input_types()
|
||||||
}
|
}
|
||||||
pub fn token_return_type() -> &'static str {
|
|
||||||
Token().return_type()
|
|
||||||
}
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub fn dynamic_result_fn(context: NativeCallContext, x: usize) -> Result<Dynamic, Box<EvalAltResult> > {
|
#[inline(always)] pub fn dynamic_result_fn(context: NativeCallContext, x: usize) -> Result<Dynamic, Box<EvalAltResult> > {
|
||||||
Ok(Dynamic::from(do_something(context, x)))
|
Ok(Dynamic::from(do_something(context, x)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -444,40 +428,35 @@ mod generate_tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
struct Token();
|
struct Token();
|
||||||
impl PluginFunction for Token {
|
impl PluginFunction for Token {
|
||||||
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result<Dynamic, Box<EvalAltResult>> {
|
#[inline(always)]
|
||||||
|
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
|
||||||
debug_assert_eq!(args.len(), 0usize,
|
debug_assert_eq!(args.len(), 0usize,
|
||||||
"wrong arg count: {} != {}", args.len(), 0usize);
|
"wrong arg count: {} != {}", args.len(), 0usize);
|
||||||
Ok(return_dynamic())
|
Ok(Dynamic::from(return_dynamic()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_method_call(&self) -> bool { false }
|
#[inline(always)] fn is_method_call(&self) -> bool { false }
|
||||||
fn is_variadic(&self) -> bool { false }
|
#[inline(always)] fn is_variadic(&self) -> bool { false }
|
||||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> { Box::new(Token()) }
|
#[inline(always)] fn clone_boxed(&self) -> Box<dyn PluginFunction> { Box::new(Token()) }
|
||||||
fn input_names(&self) -> Box<[&'static str]> {
|
#[inline(always)] fn param_names(&self) -> Box<[&'static str]> {
|
||||||
|
new_vec!["rhai::Dynamic"].into_boxed_slice()
|
||||||
|
}
|
||||||
|
#[inline(always)] fn input_types(&self) -> Box<[TypeId]> {
|
||||||
new_vec![].into_boxed_slice()
|
new_vec![].into_boxed_slice()
|
||||||
}
|
}
|
||||||
fn input_types(&self) -> Box<[TypeId]> {
|
|
||||||
new_vec![].into_boxed_slice()
|
|
||||||
}
|
}
|
||||||
fn return_type(&self) -> &'static str {
|
#[inline(always)] pub fn token_callable() -> CallableFunction {
|
||||||
"rhai::Dynamic"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn token_callable() -> CallableFunction {
|
|
||||||
Token().into()
|
Token().into()
|
||||||
}
|
}
|
||||||
pub fn token_input_names() -> Box<[&'static str]> {
|
#[inline(always)] pub fn token_param_names() -> Box<[&'static str]> {
|
||||||
Token().input_names()
|
Token().param_names()
|
||||||
}
|
}
|
||||||
pub fn token_input_types() -> Box<[TypeId]> {
|
#[inline(always)] pub fn token_input_types() -> Box<[TypeId]> {
|
||||||
Token().input_types()
|
Token().input_types()
|
||||||
}
|
}
|
||||||
pub fn token_return_type() -> &'static str {
|
|
||||||
Token().return_type()
|
|
||||||
}
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub fn dynamic_result_fn() -> Result<Dynamic, Box<EvalAltResult> > {
|
#[inline(always)] pub fn dynamic_result_fn() -> Result<Dynamic, Box<EvalAltResult> > {
|
||||||
Ok(return_dynamic())
|
Ok(Dynamic::from(return_dynamic()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -494,25 +473,23 @@ mod generate_tests {
|
|||||||
|
|
||||||
let expected_tokens = quote! {
|
let expected_tokens = quote! {
|
||||||
impl PluginFunction for TestStruct {
|
impl PluginFunction for TestStruct {
|
||||||
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result<Dynamic, Box<EvalAltResult>> {
|
#[inline(always)]
|
||||||
|
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
|
||||||
debug_assert_eq!(args.len(), 1usize,
|
debug_assert_eq!(args.len(), 1usize,
|
||||||
"wrong arg count: {} != {}", args.len(), 1usize);
|
"wrong arg count: {} != {}", args.len(), 1usize);
|
||||||
let arg0 = mem::take(args[0usize]).cast::<usize>();
|
let arg0 = mem::take(args[0usize]).cast::<usize>();
|
||||||
Ok(Dynamic::from(do_something(arg0)))
|
Ok(Dynamic::from(do_something(arg0)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_method_call(&self) -> bool { false }
|
#[inline(always)] fn is_method_call(&self) -> bool { false }
|
||||||
fn is_variadic(&self) -> bool { false }
|
#[inline(always)] fn is_variadic(&self) -> bool { false }
|
||||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> { Box::new(TestStruct()) }
|
#[inline(always)] fn clone_boxed(&self) -> Box<dyn PluginFunction> { Box::new(TestStruct()) }
|
||||||
fn input_names(&self) -> Box<[&'static str]> {
|
#[inline(always)] fn param_names(&self) -> Box<[&'static str]> {
|
||||||
new_vec!["x: usize"].into_boxed_slice()
|
new_vec!["x: usize", "()"].into_boxed_slice()
|
||||||
}
|
}
|
||||||
fn input_types(&self) -> Box<[TypeId]> {
|
#[inline(always)] fn input_types(&self) -> Box<[TypeId]> {
|
||||||
new_vec![TypeId::of::<usize>()].into_boxed_slice()
|
new_vec![TypeId::of::<usize>()].into_boxed_slice()
|
||||||
}
|
}
|
||||||
fn return_type(&self) -> &'static str {
|
|
||||||
"()"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -532,7 +509,8 @@ mod generate_tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
struct Token();
|
struct Token();
|
||||||
impl PluginFunction for Token {
|
impl PluginFunction for Token {
|
||||||
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result<Dynamic, Box<EvalAltResult>> {
|
#[inline(always)]
|
||||||
|
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
|
||||||
debug_assert_eq!(args.len(), 2usize,
|
debug_assert_eq!(args.len(), 2usize,
|
||||||
"wrong arg count: {} != {}", args.len(), 2usize);
|
"wrong arg count: {} != {}", args.len(), 2usize);
|
||||||
let arg0 = mem::take(args[0usize]).cast::<usize>();
|
let arg0 = mem::take(args[0usize]).cast::<usize>();
|
||||||
@ -540,34 +518,28 @@ mod generate_tests {
|
|||||||
Ok(Dynamic::from(add_together(arg0, arg1)))
|
Ok(Dynamic::from(add_together(arg0, arg1)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_method_call(&self) -> bool { false }
|
#[inline(always)] fn is_method_call(&self) -> bool { false }
|
||||||
fn is_variadic(&self) -> bool { false }
|
#[inline(always)] fn is_variadic(&self) -> bool { false }
|
||||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> { Box::new(Token()) }
|
#[inline(always)] fn clone_boxed(&self) -> Box<dyn PluginFunction> { Box::new(Token()) }
|
||||||
fn input_names(&self) -> Box<[&'static str]> {
|
#[inline(always)] fn param_names(&self) -> Box<[&'static str]> {
|
||||||
new_vec!["x: usize", "y: usize"].into_boxed_slice()
|
new_vec!["x: usize", "y: usize", "usize"].into_boxed_slice()
|
||||||
}
|
}
|
||||||
fn input_types(&self) -> Box<[TypeId]> {
|
#[inline(always)] fn input_types(&self) -> Box<[TypeId]> {
|
||||||
new_vec![TypeId::of::<usize>(),
|
new_vec![TypeId::of::<usize>(),
|
||||||
TypeId::of::<usize>()].into_boxed_slice()
|
TypeId::of::<usize>()].into_boxed_slice()
|
||||||
}
|
}
|
||||||
fn return_type(&self) -> &'static str {
|
|
||||||
"usize"
|
|
||||||
}
|
}
|
||||||
}
|
#[inline(always)] pub fn token_callable() -> CallableFunction {
|
||||||
pub fn token_callable() -> CallableFunction {
|
|
||||||
Token().into()
|
Token().into()
|
||||||
}
|
}
|
||||||
pub fn token_input_names() -> Box<[&'static str]> {
|
#[inline(always)] pub fn token_param_names() -> Box<[&'static str]> {
|
||||||
Token().input_names()
|
Token().param_names()
|
||||||
}
|
}
|
||||||
pub fn token_input_types() -> Box<[TypeId]> {
|
#[inline(always)] pub fn token_input_types() -> Box<[TypeId]> {
|
||||||
Token().input_types()
|
Token().input_types()
|
||||||
}
|
}
|
||||||
pub fn token_return_type() -> &'static str {
|
|
||||||
Token().return_type()
|
|
||||||
}
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub fn dynamic_result_fn(x: usize, y: usize) -> Result<Dynamic, Box<EvalAltResult> > {
|
#[inline(always)] pub fn dynamic_result_fn(x: usize, y: usize) -> Result<Dynamic, Box<EvalAltResult> > {
|
||||||
Ok(Dynamic::from(add_together(x, y)))
|
Ok(Dynamic::from(add_together(x, y)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -589,7 +561,8 @@ mod generate_tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
struct Token();
|
struct Token();
|
||||||
impl PluginFunction for Token {
|
impl PluginFunction for Token {
|
||||||
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result<Dynamic, Box<EvalAltResult>> {
|
#[inline(always)]
|
||||||
|
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
|
||||||
debug_assert_eq!(args.len(), 2usize,
|
debug_assert_eq!(args.len(), 2usize,
|
||||||
"wrong arg count: {} != {}", args.len(), 2usize);
|
"wrong arg count: {} != {}", args.len(), 2usize);
|
||||||
if args[0usize].is_read_only() {
|
if args[0usize].is_read_only() {
|
||||||
@ -602,34 +575,28 @@ mod generate_tests {
|
|||||||
Ok(Dynamic::from(increment(arg0, arg1)))
|
Ok(Dynamic::from(increment(arg0, arg1)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_method_call(&self) -> bool { true }
|
#[inline(always)] fn is_method_call(&self) -> bool { true }
|
||||||
fn is_variadic(&self) -> bool { false }
|
#[inline(always)] fn is_variadic(&self) -> bool { false }
|
||||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> { Box::new(Token()) }
|
#[inline(always)] fn clone_boxed(&self) -> Box<dyn PluginFunction> { Box::new(Token()) }
|
||||||
fn input_names(&self) -> Box<[&'static str]> {
|
#[inline(always)] fn param_names(&self) -> Box<[&'static str]> {
|
||||||
new_vec!["x: &mut usize", "y: usize"].into_boxed_slice()
|
new_vec!["x: &mut usize", "y: usize", "()"].into_boxed_slice()
|
||||||
}
|
}
|
||||||
fn input_types(&self) -> Box<[TypeId]> {
|
#[inline(always)] fn input_types(&self) -> Box<[TypeId]> {
|
||||||
new_vec![TypeId::of::<usize>(),
|
new_vec![TypeId::of::<usize>(),
|
||||||
TypeId::of::<usize>()].into_boxed_slice()
|
TypeId::of::<usize>()].into_boxed_slice()
|
||||||
}
|
}
|
||||||
fn return_type(&self) -> &'static str {
|
|
||||||
"()"
|
|
||||||
}
|
}
|
||||||
}
|
#[inline(always)] pub fn token_callable() -> CallableFunction {
|
||||||
pub fn token_callable() -> CallableFunction {
|
|
||||||
Token().into()
|
Token().into()
|
||||||
}
|
}
|
||||||
pub fn token_input_names() -> Box<[&'static str]> {
|
#[inline(always)] pub fn token_param_names() -> Box<[&'static str]> {
|
||||||
Token().input_names()
|
Token().param_names()
|
||||||
}
|
}
|
||||||
pub fn token_input_types() -> Box<[TypeId]> {
|
#[inline(always)] pub fn token_input_types() -> Box<[TypeId]> {
|
||||||
Token().input_types()
|
Token().input_types()
|
||||||
}
|
}
|
||||||
pub fn token_return_type() -> &'static str {
|
|
||||||
Token().return_type()
|
|
||||||
}
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub fn dynamic_result_fn(x: &mut usize, y: usize) -> Result<Dynamic, Box<EvalAltResult> > {
|
#[inline(always)] pub fn dynamic_result_fn(x: &mut usize, y: usize) -> Result<Dynamic, Box<EvalAltResult> > {
|
||||||
Ok(Dynamic::from(increment(x, y)))
|
Ok(Dynamic::from(increment(x, y)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -652,40 +619,35 @@ mod generate_tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
struct Token();
|
struct Token();
|
||||||
impl PluginFunction for Token {
|
impl PluginFunction for Token {
|
||||||
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result<Dynamic, Box<EvalAltResult>> {
|
#[inline(always)]
|
||||||
|
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
|
||||||
debug_assert_eq!(args.len(), 1usize,
|
debug_assert_eq!(args.len(), 1usize,
|
||||||
"wrong arg count: {} != {}", args.len(), 1usize);
|
"wrong arg count: {} != {}", args.len(), 1usize);
|
||||||
let arg0 = mem::take(args[0usize]).take_immutable_string().unwrap();
|
let arg0 = mem::take(args[0usize]).take_immutable_string().unwrap();
|
||||||
Ok(Dynamic::from(special_print(&arg0)))
|
Ok(Dynamic::from(special_print(&arg0)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_method_call(&self) -> bool { false }
|
#[inline(always)] fn is_method_call(&self) -> bool { false }
|
||||||
fn is_variadic(&self) -> bool { false }
|
#[inline(always)] fn is_variadic(&self) -> bool { false }
|
||||||
fn clone_boxed(&self) -> Box<dyn PluginFunction> { Box::new(Token()) }
|
#[inline(always)] fn clone_boxed(&self) -> Box<dyn PluginFunction> { Box::new(Token()) }
|
||||||
fn input_names(&self) -> Box<[&'static str]> {
|
#[inline(always)] fn param_names(&self) -> Box<[&'static str]> {
|
||||||
new_vec!["message: &str"].into_boxed_slice()
|
new_vec!["message: &str", "()"].into_boxed_slice()
|
||||||
}
|
}
|
||||||
fn input_types(&self) -> Box<[TypeId]> {
|
#[inline(always)] fn input_types(&self) -> Box<[TypeId]> {
|
||||||
new_vec![TypeId::of::<ImmutableString>()].into_boxed_slice()
|
new_vec![TypeId::of::<ImmutableString>()].into_boxed_slice()
|
||||||
}
|
}
|
||||||
fn return_type(&self) -> &'static str {
|
|
||||||
"()"
|
|
||||||
}
|
}
|
||||||
}
|
#[inline(always)] pub fn token_callable() -> CallableFunction {
|
||||||
pub fn token_callable() -> CallableFunction {
|
|
||||||
Token().into()
|
Token().into()
|
||||||
}
|
}
|
||||||
pub fn token_input_names() -> Box<[&'static str]> {
|
#[inline(always)] pub fn token_param_names() -> Box<[&'static str]> {
|
||||||
Token().input_names()
|
Token().param_names()
|
||||||
}
|
}
|
||||||
pub fn token_input_types() -> Box<[TypeId]> {
|
#[inline(always)] pub fn token_input_types() -> Box<[TypeId]> {
|
||||||
Token().input_types()
|
Token().input_types()
|
||||||
}
|
}
|
||||||
pub fn token_return_type() -> &'static str {
|
|
||||||
Token().return_type()
|
|
||||||
}
|
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub fn dynamic_result_fn(message: &str) -> Result<Dynamic, Box<EvalAltResult> > {
|
#[inline(always)] pub fn dynamic_result_fn(message: &str) -> Result<Dynamic, Box<EvalAltResult> > {
|
||||||
Ok(Dynamic::from(special_print(message)))
|
Ok(Dynamic::from(special_print(message)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,3 @@
|
|||||||
use rhai::module_resolvers::*;
|
|
||||||
use rhai::plugin::*;
|
use rhai::plugin::*;
|
||||||
use rhai::{Engine, EvalAltResult, Module, FLOAT};
|
use rhai::{Engine, EvalAltResult, Module, FLOAT};
|
||||||
|
|
||||||
@ -152,10 +151,8 @@ pub mod raw_returning_fn {
|
|||||||
y1: FLOAT,
|
y1: FLOAT,
|
||||||
x2: FLOAT,
|
x2: FLOAT,
|
||||||
y2: FLOAT,
|
y2: FLOAT,
|
||||||
) -> Result<rhai::Dynamic, Box<rhai::EvalAltResult>> {
|
) -> Result<rhai::FLOAT, Box<rhai::EvalAltResult>> {
|
||||||
Ok(Dynamic::from(
|
Ok(((y2 - y1).abs().powf(2.0) + (x2 - x1).abs().powf(2.0)).sqrt())
|
||||||
((y2 - y1).abs().powf(2.0) + (x2 - x1).abs().powf(2.0)).sqrt(),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
use rhai::module_resolvers::*;
|
|
||||||
use rhai::{Array, Engine, EvalAltResult, FLOAT, INT};
|
use rhai::{Array, Engine, EvalAltResult, FLOAT, INT};
|
||||||
|
|
||||||
pub mod empty_module {
|
pub mod empty_module {
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
use rhai::module_resolvers::*;
|
use rhai::{Array, Engine, EvalAltResult, FLOAT};
|
||||||
use rhai::{Array, Engine, EvalAltResult, FLOAT, INT};
|
|
||||||
|
|
||||||
pub mod one_fn_module_nested_attr {
|
pub mod one_fn_module_nested_attr {
|
||||||
use rhai::plugin::*;
|
use rhai::plugin::*;
|
||||||
@ -10,8 +9,8 @@ pub mod one_fn_module_nested_attr {
|
|||||||
use rhai::FLOAT;
|
use rhai::FLOAT;
|
||||||
|
|
||||||
#[rhai_fn(return_raw)]
|
#[rhai_fn(return_raw)]
|
||||||
pub fn get_mystic_number() -> Result<Dynamic, Box<EvalAltResult>> {
|
pub fn get_mystic_number() -> Result<FLOAT, Box<EvalAltResult>> {
|
||||||
Ok(Dynamic::from(42.0 as FLOAT))
|
Ok(42.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -39,8 +38,8 @@ pub mod one_fn_sub_module_nested_attr {
|
|||||||
use rhai::plugin::*;
|
use rhai::plugin::*;
|
||||||
use rhai::FLOAT;
|
use rhai::FLOAT;
|
||||||
#[rhai_fn(return_raw)]
|
#[rhai_fn(return_raw)]
|
||||||
pub fn get_mystic_number() -> Result<Dynamic, Box<EvalAltResult>> {
|
pub fn get_mystic_number() -> Result<FLOAT, Box<EvalAltResult>> {
|
||||||
Ok(Dynamic::from(42.0 as FLOAT))
|
Ok(42.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
error: functions marked with 'return_raw' must return Result<Dynamic, Box<EvalAltResult>>
|
error: functions marked with 'return_raw' must return Result<T, Box<EvalAltResult>>
|
||||||
--> $DIR/export_fn_raw_noreturn.rs:9:13
|
--> $DIR/export_fn_raw_noreturn.rs:9:13
|
||||||
|
|
|
|
||||||
9 | #[export_fn(return_raw)]
|
9 | #[export_fn(return_raw)]
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
error[E0308]: mismatched types
|
error[E0599]: the method `map` exists for type `bool`, but its trait bounds were not satisfied
|
||||||
--> $DIR/export_fn_raw_return.rs:10:8
|
--> $DIR/export_fn_raw_return.rs:10:33
|
||||||
|
|
|
|
||||||
9 | #[export_fn(return_raw)]
|
|
||||||
| ------------------------ expected `Result<rhai::Dynamic, std::boxed::Box<rhai::EvalAltResult>>` because of return type
|
|
||||||
10 | pub fn test_fn(input: Point) -> bool {
|
10 | pub fn test_fn(input: Point) -> bool {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `Result`, found `bool`
|
| ^^^^ method cannot be called on `bool` due to unsatisfied trait bounds
|
||||||
|
|
|
|
||||||
= note: expected enum `Result<rhai::Dynamic, std::boxed::Box<rhai::EvalAltResult>>`
|
= note: the following trait bounds were not satisfied:
|
||||||
found type `bool`
|
`bool: std::iter::Iterator`
|
||||||
|
which is required by `&mut bool: std::iter::Iterator`
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
error: functions marked with 'return_raw' must return Result<Dynamic, Box<EvalAltResult>>
|
error: functions marked with 'return_raw' must return Result<T, Box<EvalAltResult>>
|
||||||
--> $DIR/export_mod_raw_noreturn.rs:11:11
|
--> $DIR/export_mod_raw_noreturn.rs:11:11
|
||||||
|
|
|
|
||||||
11 | #[rhai_fn(return_raw)]
|
11 | #[rhai_fn(return_raw)]
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
error[E0308]: mismatched types
|
error[E0599]: the method `map` exists for type `bool`, but its trait bounds were not satisfied
|
||||||
--> $DIR/export_mod_raw_return.rs:12:8
|
--> $DIR/export_mod_raw_return.rs:12:33
|
||||||
|
|
|
|
||||||
9 | #[export_module]
|
|
||||||
| ---------------- expected `Result<rhai::Dynamic, std::boxed::Box<rhai::EvalAltResult>>` because of return type
|
|
||||||
...
|
|
||||||
12 | pub fn test_fn(input: Point) -> bool {
|
12 | pub fn test_fn(input: Point) -> bool {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `Result`, found `bool`
|
| ^^^^ method cannot be called on `bool` due to unsatisfied trait bounds
|
||||||
|
|
|
|
||||||
= note: expected enum `Result<rhai::Dynamic, std::boxed::Box<rhai::EvalAltResult>>`
|
= note: the following trait bounds were not satisfied:
|
||||||
found type `bool`
|
`bool: std::iter::Iterator`
|
||||||
|
which is required by `&mut bool: std::iter::Iterator`
|
||||||
|
@ -6,5 +6,5 @@ error[E0277]: the trait bound `NonClonable: Clone` is not satisfied
|
|||||||
|
|
|
|
||||||
::: $WORKSPACE/src/dynamic.rs
|
::: $WORKSPACE/src/dynamic.rs
|
||||||
|
|
|
|
||||||
| pub fn from<T: Variant + Clone>(value: T) -> Self {
|
| pub fn from<T: Variant + Clone>(mut value: T) -> Self {
|
||||||
| ----- required by this bound in `rhai::Dynamic::from`
|
| ----- required by this bound in `rhai::Dynamic::from`
|
||||||
|
@ -6,5 +6,5 @@ error[E0277]: the trait bound `NonClonable: Clone` is not satisfied
|
|||||||
|
|
|
|
||||||
::: $WORKSPACE/src/dynamic.rs
|
::: $WORKSPACE/src/dynamic.rs
|
||||||
|
|
|
|
||||||
| pub fn from<T: Variant + Clone>(value: T) -> Self {
|
| pub fn from<T: Variant + Clone>(mut value: T) -> Self {
|
||||||
| ----- required by this bound in `rhai::Dynamic::from`
|
| ----- required by this bound in `rhai::Dynamic::from`
|
||||||
|
23
src/ast.rs
23
src/ast.rs
@ -6,6 +6,7 @@ use crate::module::NamespaceRef;
|
|||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
boxed::Box,
|
boxed::Box,
|
||||||
|
collections::BTreeMap,
|
||||||
fmt,
|
fmt,
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
num::NonZeroUsize,
|
num::NonZeroUsize,
|
||||||
@ -15,7 +16,6 @@ use crate::stdlib::{
|
|||||||
vec::Vec,
|
vec::Vec,
|
||||||
};
|
};
|
||||||
use crate::token::Token;
|
use crate::token::Token;
|
||||||
use crate::utils::{HashableHashMap, StraightHasherBuilder};
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Dynamic, FnNamespace, FnPtr, ImmutableString, Module, Position, Shared, StaticVec, INT,
|
Dynamic, FnNamespace, FnPtr, ImmutableString, Module, Position, Shared, StaticVec, INT,
|
||||||
};
|
};
|
||||||
@ -866,14 +866,7 @@ pub enum Stmt {
|
|||||||
/// `if` expr `{` stmt `}` `else` `{` stmt `}`
|
/// `if` expr `{` stmt `}` `else` `{` stmt `}`
|
||||||
If(Expr, Box<(StmtBlock, StmtBlock)>, Position),
|
If(Expr, Box<(StmtBlock, StmtBlock)>, Position),
|
||||||
/// `switch` expr `{` literal or _ `=>` stmt `,` ... `}`
|
/// `switch` expr `{` literal or _ `=>` stmt `,` ... `}`
|
||||||
Switch(
|
Switch(Expr, Box<(BTreeMap<u64, StmtBlock>, StmtBlock)>, Position),
|
||||||
Expr,
|
|
||||||
Box<(
|
|
||||||
HashableHashMap<u64, StmtBlock, StraightHasherBuilder>,
|
|
||||||
StmtBlock,
|
|
||||||
)>,
|
|
||||||
Position,
|
|
||||||
),
|
|
||||||
/// `while` expr `{` stmt `}`
|
/// `while` expr `{` stmt `}`
|
||||||
While(Expr, Box<StmtBlock>, Position),
|
While(Expr, Box<StmtBlock>, Position),
|
||||||
/// `do` `{` stmt `}` `while`|`until` expr
|
/// `do` `{` stmt `}` `while`|`until` expr
|
||||||
@ -1303,7 +1296,7 @@ pub struct OpAssignment {
|
|||||||
///
|
///
|
||||||
/// Two separate hashes are pre-calculated because of the following pattern:
|
/// Two separate hashes are pre-calculated because of the following pattern:
|
||||||
///
|
///
|
||||||
/// ```,ignore
|
/// ```ignore
|
||||||
/// func(a, b, c); // Native: func(a, b, c) - 3 parameters
|
/// func(a, b, c); // Native: func(a, b, c) - 3 parameters
|
||||||
/// // Script: func(a, b, c) - 3 parameters
|
/// // Script: func(a, b, c) - 3 parameters
|
||||||
///
|
///
|
||||||
@ -1594,20 +1587,14 @@ impl Expr {
|
|||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Self::Array(x, _) if self.is_constant() => {
|
Self::Array(x, _) if self.is_constant() => {
|
||||||
let mut arr = Array::with_capacity(crate::stdlib::cmp::max(
|
let mut arr = Array::with_capacity(x.len());
|
||||||
crate::engine::TYPICAL_ARRAY_SIZE,
|
|
||||||
x.len(),
|
|
||||||
));
|
|
||||||
arr.extend(x.iter().map(|v| v.get_constant_value().unwrap()));
|
arr.extend(x.iter().map(|v| v.get_constant_value().unwrap()));
|
||||||
Dynamic(Union::Array(Box::new(arr), AccessMode::ReadOnly))
|
Dynamic(Union::Array(Box::new(arr), AccessMode::ReadOnly))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Self::Map(x, _) if self.is_constant() => {
|
Self::Map(x, _) if self.is_constant() => {
|
||||||
let mut map = Map::with_capacity(crate::stdlib::cmp::max(
|
let mut map = Map::new();
|
||||||
crate::engine::TYPICAL_MAP_SIZE,
|
|
||||||
x.len(),
|
|
||||||
));
|
|
||||||
map.extend(
|
map.extend(
|
||||||
x.iter()
|
x.iter()
|
||||||
.map(|(k, v)| (k.name.clone(), v.get_constant_value().unwrap())),
|
.map(|(k, v)| (k.name.clone(), v.get_constant_value().unwrap())),
|
||||||
|
@ -61,6 +61,7 @@ fn main() {
|
|||||||
let mut engine = Engine::new();
|
let mut engine = Engine::new();
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
#[cfg(not(feature = "no_std"))]
|
||||||
{
|
{
|
||||||
// Set a file module resolver without caching
|
// Set a file module resolver without caching
|
||||||
let mut resolver = rhai::module_resolvers::FileModuleResolver::new();
|
let mut resolver = rhai::module_resolvers::FileModuleResolver::new();
|
||||||
|
@ -812,8 +812,8 @@ impl Dynamic {
|
|||||||
/// A [`Vec<T>`][Vec] does not get automatically converted to an [`Array`], but will be a generic
|
/// A [`Vec<T>`][Vec] does not get automatically converted to an [`Array`], but will be a generic
|
||||||
/// restricted trait object instead, because [`Vec<T>`][Vec] is not a supported standard type.
|
/// restricted trait object instead, because [`Vec<T>`][Vec] is not a supported standard type.
|
||||||
///
|
///
|
||||||
/// Similarly, passing in a [`HashMap<String, T>`][std::collections::HashMap] will not get a [`Map`]
|
/// Similarly, passing in a [`HashMap<String, T>`][std::collections::HashMap] or
|
||||||
/// but a trait object.
|
/// [`BTreeMap<String, T>`][std::collections::BTreeMap] will not get a [`Map`] but a trait object.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
@ -833,9 +833,13 @@ impl Dynamic {
|
|||||||
/// assert_eq!(new_result.to_string(), "hello");
|
/// assert_eq!(new_result.to_string(), "hello");
|
||||||
/// ```
|
/// ```
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn from<T: Variant + Clone>(value: T) -> Self {
|
pub fn from<T: Variant + Clone>(mut value: T) -> Self {
|
||||||
// Coded this way in order to maximally leverage potentials for dead-code removal.
|
// Coded this way in order to maximally leverage potentials for dead-code removal.
|
||||||
|
|
||||||
|
if TypeId::of::<T>() == TypeId::of::<Dynamic>() {
|
||||||
|
return unsafe_try_cast::<_, Dynamic>(value).ok().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
if TypeId::of::<T>() == TypeId::of::<INT>() {
|
if TypeId::of::<T>() == TypeId::of::<INT>() {
|
||||||
return <dyn Any>::downcast_ref::<INT>(&value)
|
return <dyn Any>::downcast_ref::<INT>(&value)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -884,46 +888,43 @@ impl Dynamic {
|
|||||||
return ().into();
|
return ().into();
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut boxed = Box::new(value);
|
value = match unsafe_try_cast::<_, String>(value) {
|
||||||
|
Ok(s) => return (s).into(),
|
||||||
boxed = match unsafe_cast_box::<_, Dynamic>(boxed) {
|
|
||||||
Ok(d) => return *d,
|
|
||||||
Err(val) => val,
|
|
||||||
};
|
|
||||||
boxed = match unsafe_cast_box::<_, String>(boxed) {
|
|
||||||
Ok(s) => return (*s).into(),
|
|
||||||
Err(val) => val,
|
Err(val) => val,
|
||||||
};
|
};
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
{
|
{
|
||||||
boxed = match unsafe_cast_box::<_, Array>(boxed) {
|
value = match unsafe_try_cast::<_, Array>(value) {
|
||||||
Ok(array) => return (*array).into(),
|
Ok(array) => return (array).into(),
|
||||||
Err(val) => val,
|
Err(val) => val,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
{
|
{
|
||||||
boxed = match unsafe_cast_box::<_, Map>(boxed) {
|
value = match unsafe_try_cast::<_, Map>(value) {
|
||||||
Ok(map) => return (*map).into(),
|
Ok(map) => return (map).into(),
|
||||||
Err(val) => val,
|
Err(val) => val,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boxed = match unsafe_cast_box::<_, FnPtr>(boxed) {
|
value = match unsafe_try_cast::<_, FnPtr>(value) {
|
||||||
Ok(fn_ptr) => return (*fn_ptr).into(),
|
Ok(fn_ptr) => return (fn_ptr).into(),
|
||||||
Err(val) => val,
|
Err(val) => val,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_std"))]
|
#[cfg(not(feature = "no_std"))]
|
||||||
{
|
{
|
||||||
boxed = match unsafe_cast_box::<_, Instant>(boxed) {
|
value = match unsafe_try_cast::<_, Instant>(value) {
|
||||||
Ok(timestamp) => return (*timestamp).into(),
|
Ok(timestamp) => return (timestamp).into(),
|
||||||
Err(val) => val,
|
Err(val) => val,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Self(Union::Variant(Box::new(boxed), AccessMode::ReadWrite))
|
Self(Union::Variant(
|
||||||
|
Box::new(Box::new(value)),
|
||||||
|
AccessMode::ReadWrite,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
/// Turn the [`Dynamic`] value into a shared [`Dynamic`] value backed by an
|
/// Turn the [`Dynamic`] value into a shared [`Dynamic`] value backed by an
|
||||||
/// [`Rc`][std::rc::Rc]`<`[`RefCell`][std::cell::RefCell]`<`[`Dynamic`]`>>` or
|
/// [`Rc`][std::rc::Rc]`<`[`RefCell`][std::cell::RefCell]`<`[`Dynamic`]`>>` or
|
||||||
@ -986,12 +987,12 @@ impl Dynamic {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if TypeId::of::<T>() == TypeId::of::<Dynamic>() {
|
if TypeId::of::<T>() == TypeId::of::<Dynamic>() {
|
||||||
return unsafe_cast_box::<_, T>(Box::new(self)).ok().map(|v| *v);
|
return unsafe_try_cast::<_, T>(self).ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
if TypeId::of::<T>() == TypeId::of::<INT>() {
|
if TypeId::of::<T>() == TypeId::of::<INT>() {
|
||||||
return match self.0 {
|
return match self.0 {
|
||||||
Union::Int(value, _) => unsafe_try_cast(value),
|
Union::Int(value, _) => unsafe_try_cast(value).ok(),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -999,7 +1000,7 @@ impl Dynamic {
|
|||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
if TypeId::of::<T>() == TypeId::of::<FLOAT>() {
|
if TypeId::of::<T>() == TypeId::of::<FLOAT>() {
|
||||||
return match self.0 {
|
return match self.0 {
|
||||||
Union::Float(value, _) => unsafe_try_cast(*value),
|
Union::Float(value, _) => unsafe_try_cast(*value).ok(),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -1007,35 +1008,35 @@ impl Dynamic {
|
|||||||
#[cfg(feature = "decimal")]
|
#[cfg(feature = "decimal")]
|
||||||
if TypeId::of::<T>() == TypeId::of::<Decimal>() {
|
if TypeId::of::<T>() == TypeId::of::<Decimal>() {
|
||||||
return match self.0 {
|
return match self.0 {
|
||||||
Union::Decimal(value, _) => unsafe_try_cast(*value),
|
Union::Decimal(value, _) => unsafe_try_cast(*value).ok(),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if TypeId::of::<T>() == TypeId::of::<bool>() {
|
if TypeId::of::<T>() == TypeId::of::<bool>() {
|
||||||
return match self.0 {
|
return match self.0 {
|
||||||
Union::Bool(value, _) => unsafe_try_cast(value),
|
Union::Bool(value, _) => unsafe_try_cast(value).ok(),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if TypeId::of::<T>() == TypeId::of::<ImmutableString>() {
|
if TypeId::of::<T>() == TypeId::of::<ImmutableString>() {
|
||||||
return match self.0 {
|
return match self.0 {
|
||||||
Union::Str(value, _) => unsafe_try_cast(value),
|
Union::Str(value, _) => unsafe_try_cast(value).ok(),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if TypeId::of::<T>() == TypeId::of::<String>() {
|
if TypeId::of::<T>() == TypeId::of::<String>() {
|
||||||
return match self.0 {
|
return match self.0 {
|
||||||
Union::Str(value, _) => unsafe_try_cast(value.into_owned()),
|
Union::Str(value, _) => unsafe_try_cast(value.into_owned()).ok(),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if TypeId::of::<T>() == TypeId::of::<char>() {
|
if TypeId::of::<T>() == TypeId::of::<char>() {
|
||||||
return match self.0 {
|
return match self.0 {
|
||||||
Union::Char(value, _) => unsafe_try_cast(value),
|
Union::Char(value, _) => unsafe_try_cast(value).ok(),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -1073,7 +1074,7 @@ impl Dynamic {
|
|||||||
|
|
||||||
if TypeId::of::<T>() == TypeId::of::<()>() {
|
if TypeId::of::<T>() == TypeId::of::<()>() {
|
||||||
return match self.0 {
|
return match self.0 {
|
||||||
Union::Unit(value, _) => unsafe_try_cast(value),
|
Union::Unit(value, _) => unsafe_try_cast(value).ok(),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -1695,6 +1696,7 @@ impl<T: Variant + Clone> crate::stdlib::iter::FromIterator<T> for Dynamic {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
#[cfg(not(feature = "no_std"))]
|
||||||
impl<K: Into<ImmutableString>, T: Variant + Clone> From<crate::stdlib::collections::HashMap<K, T>>
|
impl<K: Into<ImmutableString>, T: Variant + Clone> From<crate::stdlib::collections::HashMap<K, T>>
|
||||||
for Dynamic
|
for Dynamic
|
||||||
{
|
{
|
||||||
@ -1711,6 +1713,23 @@ impl<K: Into<ImmutableString>, T: Variant + Clone> From<crate::stdlib::collectio
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
impl<K: Into<ImmutableString>, T: Variant + Clone> From<crate::stdlib::collections::BTreeMap<K, T>>
|
||||||
|
for Dynamic
|
||||||
|
{
|
||||||
|
#[inline(always)]
|
||||||
|
fn from(value: crate::stdlib::collections::BTreeMap<K, T>) -> Self {
|
||||||
|
Self(Union::Map(
|
||||||
|
Box::new(
|
||||||
|
value
|
||||||
|
.into_iter()
|
||||||
|
.map(|(k, v)| (k.into(), Dynamic::from(v)))
|
||||||
|
.collect(),
|
||||||
|
),
|
||||||
|
AccessMode::ReadWrite,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
impl From<FnPtr> for Dynamic {
|
impl From<FnPtr> for Dynamic {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn from(value: FnPtr) -> Self {
|
fn from(value: FnPtr) -> Self {
|
||||||
|
@ -14,7 +14,7 @@ use crate::stdlib::{
|
|||||||
any::{type_name, TypeId},
|
any::{type_name, TypeId},
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
boxed::Box,
|
boxed::Box,
|
||||||
collections::{HashMap, HashSet},
|
collections::{BTreeMap, BTreeSet},
|
||||||
fmt, format,
|
fmt, format,
|
||||||
hash::{Hash, Hasher},
|
hash::{Hash, Hasher},
|
||||||
num::{NonZeroU8, NonZeroUsize},
|
num::{NonZeroU8, NonZeroUsize},
|
||||||
@ -23,7 +23,7 @@ use crate::stdlib::{
|
|||||||
vec::Vec,
|
vec::Vec,
|
||||||
};
|
};
|
||||||
use crate::syntax::CustomSyntax;
|
use crate::syntax::CustomSyntax;
|
||||||
use crate::utils::{get_hasher, StraightHasherBuilder};
|
use crate::utils::get_hasher;
|
||||||
use crate::{
|
use crate::{
|
||||||
Dynamic, EvalAltResult, FnPtr, ImmutableString, Module, Position, RhaiResult, Scope, Shared,
|
Dynamic, EvalAltResult, FnPtr, ImmutableString, Module, Position, RhaiResult, Scope, Shared,
|
||||||
StaticVec,
|
StaticVec,
|
||||||
@ -32,15 +32,9 @@ use crate::{
|
|||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
use crate::{calc_fn_hash, stdlib::iter::empty, Array};
|
use crate::{calc_fn_hash, stdlib::iter::empty, Array};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
|
||||||
pub const TYPICAL_ARRAY_SIZE: usize = 8; // Small arrays are typical
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
use crate::Map;
|
use crate::Map;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
|
||||||
pub const TYPICAL_MAP_SIZE: usize = 8; // Small maps are typical
|
|
||||||
|
|
||||||
pub type Precedence = NonZeroU8;
|
pub type Precedence = NonZeroU8;
|
||||||
|
|
||||||
/// _(INTERNALS)_ A stack of imported [modules][Module].
|
/// _(INTERNALS)_ A stack of imported [modules][Module].
|
||||||
@ -501,7 +495,7 @@ pub struct FnResolutionCacheEntry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A function resolution cache.
|
/// A function resolution cache.
|
||||||
pub type FnResolutionCache = HashMap<u64, Option<FnResolutionCacheEntry>, StraightHasherBuilder>;
|
pub type FnResolutionCache = BTreeMap<u64, Option<FnResolutionCacheEntry>>;
|
||||||
|
|
||||||
/// _(INTERNALS)_ A type that holds all the current states of the [`Engine`].
|
/// _(INTERNALS)_ A type that holds all the current states of the [`Engine`].
|
||||||
/// Exported under the `internals` feature only.
|
/// Exported under the `internals` feature only.
|
||||||
@ -540,9 +534,7 @@ impl State {
|
|||||||
/// Get a mutable reference to the current function resolution cache.
|
/// Get a mutable reference to the current function resolution cache.
|
||||||
pub fn fn_resolution_cache_mut(&mut self) -> &mut FnResolutionCache {
|
pub fn fn_resolution_cache_mut(&mut self) -> &mut FnResolutionCache {
|
||||||
if self.fn_resolution_caches.0.is_empty() {
|
if self.fn_resolution_caches.0.is_empty() {
|
||||||
self.fn_resolution_caches
|
self.fn_resolution_caches.0.push(BTreeMap::new());
|
||||||
.0
|
|
||||||
.push(HashMap::with_capacity_and_hasher(64, StraightHasherBuilder));
|
|
||||||
}
|
}
|
||||||
self.fn_resolution_caches.0.last_mut().unwrap()
|
self.fn_resolution_caches.0.last_mut().unwrap()
|
||||||
}
|
}
|
||||||
@ -711,21 +703,21 @@ pub struct Engine {
|
|||||||
/// A collection of all modules loaded into the global namespace of the Engine.
|
/// A collection of all modules loaded into the global namespace of the Engine.
|
||||||
pub(crate) global_modules: StaticVec<Shared<Module>>,
|
pub(crate) global_modules: StaticVec<Shared<Module>>,
|
||||||
/// A collection of all sub-modules directly loaded into the Engine.
|
/// A collection of all sub-modules directly loaded into the Engine.
|
||||||
pub(crate) global_sub_modules: HashMap<ImmutableString, Shared<Module>>,
|
pub(crate) global_sub_modules: BTreeMap<ImmutableString, Shared<Module>>,
|
||||||
|
|
||||||
/// A module resolution service.
|
/// A module resolution service.
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
pub(crate) module_resolver: Box<dyn crate::ModuleResolver>,
|
pub(crate) module_resolver: Box<dyn crate::ModuleResolver>,
|
||||||
|
|
||||||
/// A hashmap mapping type names to pretty-print names.
|
/// A map mapping type names to pretty-print names.
|
||||||
pub(crate) type_names: HashMap<String, String>,
|
pub(crate) type_names: BTreeMap<String, String>,
|
||||||
|
|
||||||
/// A hashset containing symbols to disable.
|
/// A set of symbols to disable.
|
||||||
pub(crate) disabled_symbols: HashSet<String>,
|
pub(crate) disabled_symbols: BTreeSet<String>,
|
||||||
/// A hashmap containing custom keywords and precedence to recognize.
|
/// A map containing custom keywords and precedence to recognize.
|
||||||
pub(crate) custom_keywords: HashMap<String, Option<Precedence>>,
|
pub(crate) custom_keywords: BTreeMap<String, Option<Precedence>>,
|
||||||
/// Custom syntax.
|
/// Custom syntax.
|
||||||
pub(crate) custom_syntax: HashMap<ImmutableString, CustomSyntax>,
|
pub(crate) custom_syntax: BTreeMap<ImmutableString, CustomSyntax>,
|
||||||
/// Callback closure for resolving variable access.
|
/// Callback closure for resolving variable access.
|
||||||
pub(crate) resolve_var: Option<OnVarCallback>,
|
pub(crate) resolve_var: Option<OnVarCallback>,
|
||||||
|
|
||||||
@ -1047,12 +1039,6 @@ impl Engine {
|
|||||||
|
|
||||||
let val = scope.get_mut_by_index(index);
|
let val = scope.get_mut_by_index(index);
|
||||||
|
|
||||||
// Check for data race - probably not necessary because the only place it should conflict is
|
|
||||||
// in a method call when the object variable is also used as a parameter.
|
|
||||||
// if cfg!(not(feature = "no_closure")) && val.is_locked() {
|
|
||||||
// return EvalAltResult::ErrorDataRace(name.into(), *pos).into();
|
|
||||||
// }
|
|
||||||
|
|
||||||
Ok((val.into(), *pos))
|
Ok((val.into(), *pos))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1688,8 +1674,7 @@ impl Engine {
|
|||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Expr::Array(x, _) => {
|
Expr::Array(x, _) => {
|
||||||
let mut arr =
|
let mut arr = Array::with_capacity(x.len());
|
||||||
Array::with_capacity(crate::stdlib::cmp::max(TYPICAL_ARRAY_SIZE, x.len()));
|
|
||||||
for item in x.as_ref() {
|
for item in x.as_ref() {
|
||||||
arr.push(
|
arr.push(
|
||||||
self.eval_expr(scope, mods, state, lib, this_ptr, item, level)?
|
self.eval_expr(scope, mods, state, lib, this_ptr, item, level)?
|
||||||
@ -1701,8 +1686,7 @@ impl Engine {
|
|||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Expr::Map(x, _) => {
|
Expr::Map(x, _) => {
|
||||||
let mut map =
|
let mut map = Map::new();
|
||||||
Map::with_capacity(crate::stdlib::cmp::max(TYPICAL_MAP_SIZE, x.len()));
|
|
||||||
for (Ident { name: key, .. }, expr) in x.as_ref() {
|
for (Ident { name: key, .. }, expr) in x.as_ref() {
|
||||||
map.insert(
|
map.insert(
|
||||||
key.clone(),
|
key.clone(),
|
||||||
|
@ -880,7 +880,7 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
pub fn register_static_module(&mut self, name: &str, module: Shared<Module>) -> &mut Self {
|
pub fn register_static_module(&mut self, name: &str, module: Shared<Module>) -> &mut Self {
|
||||||
fn register_static_module_raw(
|
fn register_static_module_raw(
|
||||||
root: &mut crate::stdlib::collections::HashMap<crate::ImmutableString, Shared<Module>>,
|
root: &mut crate::stdlib::collections::BTreeMap<crate::ImmutableString, Shared<Module>>,
|
||||||
name: &str,
|
name: &str,
|
||||||
module: Shared<Module>,
|
module: Shared<Module>,
|
||||||
) {
|
) {
|
||||||
@ -1012,14 +1012,14 @@ impl Engine {
|
|||||||
ast::{ASTNode, Expr, Stmt},
|
ast::{ASTNode, Expr, Stmt},
|
||||||
fn_native::shared_take_or_clone,
|
fn_native::shared_take_or_clone,
|
||||||
module::resolvers::StaticModuleResolver,
|
module::resolvers::StaticModuleResolver,
|
||||||
stdlib::collections::HashSet,
|
stdlib::collections::BTreeSet,
|
||||||
ImmutableString,
|
ImmutableString,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn collect_imports(
|
fn collect_imports(
|
||||||
ast: &AST,
|
ast: &AST,
|
||||||
resolver: &StaticModuleResolver,
|
resolver: &StaticModuleResolver,
|
||||||
imports: &mut HashSet<ImmutableString>,
|
imports: &mut BTreeSet<ImmutableString>,
|
||||||
) {
|
) {
|
||||||
ast.walk(&mut |path| match path.last().unwrap() {
|
ast.walk(&mut |path| match path.last().unwrap() {
|
||||||
// Collect all `import` statements with a string constant path
|
// Collect all `import` statements with a string constant path
|
||||||
@ -1035,7 +1035,7 @@ impl Engine {
|
|||||||
|
|
||||||
let mut resolver = StaticModuleResolver::new();
|
let mut resolver = StaticModuleResolver::new();
|
||||||
let mut ast = self.compile_scripts_with_scope(scope, &[script])?;
|
let mut ast = self.compile_scripts_with_scope(scope, &[script])?;
|
||||||
let mut imports = HashSet::<ImmutableString>::new();
|
let mut imports = Default::default();
|
||||||
|
|
||||||
collect_imports(&ast, &mut resolver, &mut imports);
|
collect_imports(&ast, &mut resolver, &mut imports);
|
||||||
|
|
||||||
@ -1885,9 +1885,8 @@ impl Engine {
|
|||||||
.ok_or_else(|| EvalAltResult::ErrorFunctionNotFound(name.into(), Position::NONE))?;
|
.ok_or_else(|| EvalAltResult::ErrorFunctionNotFound(name.into(), Position::NONE))?;
|
||||||
|
|
||||||
// Check for data race.
|
// Check for data race.
|
||||||
if cfg!(not(feature = "no_closure")) {
|
#[cfg(not(feature = "no_closure"))]
|
||||||
crate::fn_call::ensure_no_data_race(name, args, false)?;
|
crate::fn_call::ensure_no_data_race(name, args, false)?;
|
||||||
}
|
|
||||||
|
|
||||||
self.call_script_fn(
|
self.call_script_fn(
|
||||||
scope,
|
scope,
|
||||||
|
@ -109,7 +109,7 @@ pub fn get_builtin_binary_op_fn(
|
|||||||
return Some(|_, args| {
|
return Some(|_, args| {
|
||||||
let x = args[0].$xx().unwrap() as $base;
|
let x = args[0].$xx().unwrap() as $base;
|
||||||
let y = args[1].$yy().unwrap() as $base;
|
let y = args[1].$yy().unwrap() as $base;
|
||||||
$func(x, y)
|
$func(x, y).map(Into::<Dynamic>::into)
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
(from $base:ty => $xx:ident $op:tt $yy:ident) => {
|
(from $base:ty => $xx:ident $op:tt $yy:ident) => {
|
||||||
@ -130,7 +130,7 @@ pub fn get_builtin_binary_op_fn(
|
|||||||
return Some(|_, args| {
|
return Some(|_, args| {
|
||||||
let x = <$base>::from(args[0].$xx().unwrap());
|
let x = <$base>::from(args[0].$xx().unwrap());
|
||||||
let y = <$base>::from(args[1].$yy().unwrap());
|
let y = <$base>::from(args[1].$yy().unwrap());
|
||||||
$func(x, y)
|
$func(x, y).map(Into::<Dynamic>::into)
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -102,22 +102,19 @@ pub fn ensure_no_data_race(
|
|||||||
args: &FnCallArgs,
|
args: &FnCallArgs,
|
||||||
is_ref: bool,
|
is_ref: bool,
|
||||||
) -> Result<(), Box<EvalAltResult>> {
|
) -> Result<(), Box<EvalAltResult>> {
|
||||||
if cfg!(not(feature = "no_closure")) {
|
#[cfg(not(feature = "no_closure"))]
|
||||||
let skip = if is_ref { 1 } else { 0 };
|
|
||||||
|
|
||||||
if let Some((n, _)) = args
|
if let Some((n, _)) = args
|
||||||
.iter()
|
.iter()
|
||||||
.skip(skip)
|
|
||||||
.enumerate()
|
.enumerate()
|
||||||
|
.skip(if is_ref { 1 } else { 0 })
|
||||||
.find(|(_, a)| a.is_locked())
|
.find(|(_, a)| a.is_locked())
|
||||||
{
|
{
|
||||||
return EvalAltResult::ErrorDataRace(
|
return EvalAltResult::ErrorDataRace(
|
||||||
format!("argument #{} of function '{}'", n + 1 + skip, fn_name),
|
format!("argument #{} of function '{}'", n + 1, fn_name),
|
||||||
Position::NONE,
|
Position::NONE,
|
||||||
)
|
)
|
||||||
.into();
|
.into();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -636,9 +633,8 @@ impl Engine {
|
|||||||
_level: usize,
|
_level: usize,
|
||||||
) -> Result<(Dynamic, bool), Box<EvalAltResult>> {
|
) -> Result<(Dynamic, bool), Box<EvalAltResult>> {
|
||||||
// Check for data race.
|
// Check for data race.
|
||||||
if cfg!(not(feature = "no_closure")) {
|
#[cfg(not(feature = "no_closure"))]
|
||||||
ensure_no_data_race(fn_name, args, is_ref)?;
|
ensure_no_data_race(fn_name, args, is_ref)?;
|
||||||
}
|
|
||||||
|
|
||||||
// These may be redirected from method style calls.
|
// These may be redirected from method style calls.
|
||||||
match fn_name {
|
match fn_name {
|
||||||
@ -1259,7 +1255,10 @@ impl Engine {
|
|||||||
arg_values = args_expr
|
arg_values = args_expr
|
||||||
.iter()
|
.iter()
|
||||||
.skip(1)
|
.skip(1)
|
||||||
.map(|expr| self.eval_expr(scope, mods, state, lib, this_ptr, expr, level))
|
.map(|expr| {
|
||||||
|
self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)
|
||||||
|
.map(Dynamic::flatten)
|
||||||
|
})
|
||||||
.collect::<Result<_, _>>()?;
|
.collect::<Result<_, _>>()?;
|
||||||
|
|
||||||
let (mut target, pos) =
|
let (mut target, pos) =
|
||||||
@ -1285,7 +1284,10 @@ impl Engine {
|
|||||||
// func(..., ...)
|
// func(..., ...)
|
||||||
arg_values = args_expr
|
arg_values = args_expr
|
||||||
.iter()
|
.iter()
|
||||||
.map(|expr| self.eval_expr(scope, mods, state, lib, this_ptr, expr, level))
|
.map(|expr| {
|
||||||
|
self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)
|
||||||
|
.map(Dynamic::flatten)
|
||||||
|
})
|
||||||
.collect::<Result<_, _>>()?;
|
.collect::<Result<_, _>>()?;
|
||||||
|
|
||||||
args = curry.iter_mut().chain(arg_values.iter_mut()).collect();
|
args = curry.iter_mut().chain(arg_values.iter_mut()).collect();
|
||||||
@ -1340,6 +1342,7 @@ impl Engine {
|
|||||||
Ok(Default::default())
|
Ok(Default::default())
|
||||||
} else {
|
} else {
|
||||||
self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)
|
self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)
|
||||||
|
.map(Dynamic::flatten)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect::<Result<_, _>>()?;
|
.collect::<Result<_, _>>()?;
|
||||||
@ -1364,7 +1367,10 @@ impl Engine {
|
|||||||
// func(..., ...) or func(mod::x, ...)
|
// func(..., ...) or func(mod::x, ...)
|
||||||
arg_values = args_expr
|
arg_values = args_expr
|
||||||
.iter()
|
.iter()
|
||||||
.map(|expr| self.eval_expr(scope, mods, state, lib, this_ptr, expr, level))
|
.map(|expr| {
|
||||||
|
self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)
|
||||||
|
.map(Dynamic::flatten)
|
||||||
|
})
|
||||||
.collect::<Result<_, _>>()?;
|
.collect::<Result<_, _>>()?;
|
||||||
|
|
||||||
args = arg_values.iter_mut().collect();
|
args = arg_values.iter_mut().collect();
|
||||||
|
@ -98,10 +98,7 @@ macro_rules! def_anonymous_fn {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn create_from_ast(self, ast: AST, entry_point: &str) -> Self::Output {
|
fn create_from_ast(self, ast: AST, entry_point: &str) -> Self::Output {
|
||||||
let fn_name = entry_point.to_string();
|
let fn_name = entry_point.to_string();
|
||||||
|
Box::new(move |$($par),*| self.call_fn(&mut Scope::new(), &ast, &fn_name, ($($par,)*)))
|
||||||
Box::new(move |$($par: $par),*| {
|
|
||||||
self.call_fn(&mut Scope::new(), &ast, &fn_name, ($($par,)*))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
//!
|
//!
|
||||||
//! ## Contents of `my_script.rhai`
|
//! ## Contents of `my_script.rhai`
|
||||||
//!
|
//!
|
||||||
//! ```,ignore
|
//! ```ignore
|
||||||
//! /// Brute force factorial function
|
//! /// Brute force factorial function
|
||||||
//! fn factorial(x) {
|
//! fn factorial(x) {
|
||||||
//! if x == 1 { return 1; }
|
//! if x == 1 { return 1; }
|
||||||
@ -24,7 +24,7 @@
|
|||||||
//!
|
//!
|
||||||
//! ## The Rust part
|
//! ## The Rust part
|
||||||
//!
|
//!
|
||||||
//! ```,no_run
|
//! ```no_run
|
||||||
//! use rhai::{Engine, EvalAltResult};
|
//! use rhai::{Engine, EvalAltResult};
|
||||||
//!
|
//!
|
||||||
//! fn main() -> Result<(), Box<EvalAltResult>>
|
//! fn main() -> Result<(), Box<EvalAltResult>>
|
||||||
@ -88,7 +88,7 @@ mod token;
|
|||||||
mod r#unsafe;
|
mod r#unsafe;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
type RhaiResult = Result<Dynamic, stdlib::boxed::Box<EvalAltResult>>;
|
type RhaiResult = stdlib::result::Result<Dynamic, stdlib::boxed::Box<EvalAltResult>>;
|
||||||
|
|
||||||
/// The system integer type. It is defined as [`i64`].
|
/// The system integer type. It is defined as [`i64`].
|
||||||
///
|
///
|
||||||
@ -164,7 +164,7 @@ pub type Array = stdlib::vec::Vec<Dynamic>;
|
|||||||
///
|
///
|
||||||
/// Not available under `no_object`.
|
/// Not available under `no_object`.
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
pub type Map = stdlib::collections::HashMap<ImmutableString, Dynamic>;
|
pub type Map = stdlib::collections::BTreeMap<ImmutableString, Dynamic>;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
pub use module::ModuleResolver;
|
pub use module::ModuleResolver;
|
||||||
|
@ -7,7 +7,7 @@ use crate::fn_register::RegisterNativeFunction;
|
|||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
any::TypeId,
|
any::TypeId,
|
||||||
boxed::Box,
|
boxed::Box,
|
||||||
collections::HashMap,
|
collections::BTreeMap,
|
||||||
fmt, format,
|
fmt, format,
|
||||||
iter::empty,
|
iter::empty,
|
||||||
num::NonZeroUsize,
|
num::NonZeroUsize,
|
||||||
@ -16,7 +16,6 @@ use crate::stdlib::{
|
|||||||
vec::Vec,
|
vec::Vec,
|
||||||
};
|
};
|
||||||
use crate::token::Token;
|
use crate::token::Token;
|
||||||
use crate::utils::StraightHasherBuilder;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
calc_fn_hash, calc_fn_params_hash, combine_hashes, Dynamic, EvalAltResult, ImmutableString,
|
calc_fn_hash, calc_fn_params_hash, combine_hashes, Dynamic, EvalAltResult, ImmutableString,
|
||||||
NativeCallContext, Position, Shared, StaticVec,
|
NativeCallContext, Position, Shared, StaticVec,
|
||||||
@ -130,20 +129,20 @@ pub struct Module {
|
|||||||
/// ID identifying the module.
|
/// ID identifying the module.
|
||||||
id: Option<ImmutableString>,
|
id: Option<ImmutableString>,
|
||||||
/// Sub-modules.
|
/// Sub-modules.
|
||||||
modules: HashMap<ImmutableString, Shared<Module>>,
|
modules: BTreeMap<ImmutableString, Shared<Module>>,
|
||||||
/// [`Module`] variables.
|
/// [`Module`] variables.
|
||||||
variables: HashMap<ImmutableString, Dynamic>,
|
variables: BTreeMap<ImmutableString, Dynamic>,
|
||||||
/// Flattened collection of all [`Module`] variables, including those in sub-modules.
|
/// Flattened collection of all [`Module`] variables, including those in sub-modules.
|
||||||
all_variables: HashMap<u64, Dynamic, StraightHasherBuilder>,
|
all_variables: BTreeMap<u64, Dynamic>,
|
||||||
/// External Rust functions.
|
/// External Rust functions.
|
||||||
functions: HashMap<u64, Box<FuncInfo>, StraightHasherBuilder>,
|
functions: BTreeMap<u64, Box<FuncInfo>>,
|
||||||
/// Flattened collection of all external Rust functions, native or scripted.
|
/// Flattened collection of all external Rust functions, native or scripted.
|
||||||
/// including those in sub-modules.
|
/// including those in sub-modules.
|
||||||
all_functions: HashMap<u64, CallableFunction, StraightHasherBuilder>,
|
all_functions: BTreeMap<u64, CallableFunction>,
|
||||||
/// Iterator functions, keyed by the type producing the iterator.
|
/// Iterator functions, keyed by the type producing the iterator.
|
||||||
type_iterators: HashMap<TypeId, IteratorFn>,
|
type_iterators: BTreeMap<TypeId, IteratorFn>,
|
||||||
/// Flattened collection of iterator functions, including those in sub-modules.
|
/// Flattened collection of iterator functions, including those in sub-modules.
|
||||||
all_type_iterators: HashMap<TypeId, IteratorFn>,
|
all_type_iterators: BTreeMap<TypeId, IteratorFn>,
|
||||||
/// Is the [`Module`] indexed?
|
/// Is the [`Module`] indexed?
|
||||||
indexed: bool,
|
indexed: bool,
|
||||||
/// Does the [`Module`] contain indexed functions that have been exposed to the global namespace?
|
/// Does the [`Module`] contain indexed functions that have been exposed to the global namespace?
|
||||||
@ -158,8 +157,8 @@ impl Default for Module {
|
|||||||
modules: Default::default(),
|
modules: Default::default(),
|
||||||
variables: Default::default(),
|
variables: Default::default(),
|
||||||
all_variables: Default::default(),
|
all_variables: Default::default(),
|
||||||
functions: HashMap::with_capacity_and_hasher(64, StraightHasherBuilder),
|
functions: Default::default(),
|
||||||
all_functions: HashMap::with_capacity_and_hasher(256, StraightHasherBuilder),
|
all_functions: Default::default(),
|
||||||
type_iterators: Default::default(),
|
type_iterators: Default::default(),
|
||||||
all_type_iterators: Default::default(),
|
all_type_iterators: Default::default(),
|
||||||
indexed: false,
|
indexed: false,
|
||||||
@ -270,25 +269,6 @@ impl Module {
|
|||||||
Default::default()
|
Default::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new [`Module`] with a specified capacity for native Rust functions.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use rhai::Module;
|
|
||||||
///
|
|
||||||
/// let mut module = Module::new();
|
|
||||||
/// module.set_var("answer", 42_i64);
|
|
||||||
/// assert_eq!(module.get_var_value::<i64>("answer").unwrap(), 42);
|
|
||||||
/// ```
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn new_with_capacity(capacity: usize) -> Self {
|
|
||||||
Self {
|
|
||||||
functions: HashMap::with_capacity_and_hasher(capacity, StraightHasherBuilder),
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the ID of the [`Module`], if any.
|
/// Get the ID of the [`Module`], if any.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
@ -520,7 +500,7 @@ impl Module {
|
|||||||
.map(|f| f.func.get_fn_def())
|
.map(|f| f.func.get_fn_def())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a mutable reference to the underlying [`HashMap`] of sub-modules.
|
/// Get a mutable reference to the underlying [`BTreeMap`] of sub-modules.
|
||||||
///
|
///
|
||||||
/// # WARNING
|
/// # WARNING
|
||||||
///
|
///
|
||||||
@ -528,7 +508,7 @@ impl Module {
|
|||||||
/// Thus the [`Module`] is automatically set to be non-indexed.
|
/// Thus the [`Module`] is automatically set to be non-indexed.
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn sub_modules_mut(&mut self) -> &mut HashMap<ImmutableString, Shared<Module>> {
|
pub(crate) fn sub_modules_mut(&mut self) -> &mut BTreeMap<ImmutableString, Shared<Module>> {
|
||||||
// We must assume that the user has changed the sub-modules
|
// We must assume that the user has changed the sub-modules
|
||||||
// (otherwise why take a mutable reference?)
|
// (otherwise why take a mutable reference?)
|
||||||
self.all_functions.clear();
|
self.all_functions.clear();
|
||||||
@ -1235,13 +1215,16 @@ impl Module {
|
|||||||
&mut self,
|
&mut self,
|
||||||
filter: impl Fn(FnNamespace, FnAccess, &str, usize) -> bool,
|
filter: impl Fn(FnNamespace, FnAccess, &str, usize) -> bool,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
self.functions.retain(|_, f| {
|
self.functions = crate::stdlib::mem::take(&mut self.functions)
|
||||||
|
.into_iter()
|
||||||
|
.filter(|(_, f)| {
|
||||||
if f.func.is_script() {
|
if f.func.is_script() {
|
||||||
filter(f.namespace, f.access, f.name.as_str(), f.params)
|
filter(f.namespace, f.access, f.name.as_str(), f.params)
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
self.all_functions.clear();
|
self.all_functions.clear();
|
||||||
self.all_variables.clear();
|
self.all_variables.clear();
|
||||||
@ -1460,9 +1443,9 @@ impl Module {
|
|||||||
fn index_module<'a>(
|
fn index_module<'a>(
|
||||||
module: &'a Module,
|
module: &'a Module,
|
||||||
path: &mut Vec<&'a str>,
|
path: &mut Vec<&'a str>,
|
||||||
variables: &mut HashMap<u64, Dynamic, StraightHasherBuilder>,
|
variables: &mut BTreeMap<u64, Dynamic>,
|
||||||
functions: &mut HashMap<u64, CallableFunction, StraightHasherBuilder>,
|
functions: &mut BTreeMap<u64, CallableFunction>,
|
||||||
type_iterators: &mut HashMap<TypeId, IteratorFn>,
|
type_iterators: &mut BTreeMap<TypeId, IteratorFn>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let mut contains_indexed_global_functions = false;
|
let mut contains_indexed_global_functions = false;
|
||||||
|
|
||||||
@ -1518,9 +1501,9 @@ impl Module {
|
|||||||
|
|
||||||
if !self.indexed {
|
if !self.indexed {
|
||||||
let mut path = Vec::with_capacity(4);
|
let mut path = Vec::with_capacity(4);
|
||||||
let mut variables = HashMap::with_capacity_and_hasher(16, StraightHasherBuilder);
|
let mut variables = Default::default();
|
||||||
let mut functions = HashMap::with_capacity_and_hasher(256, StraightHasherBuilder);
|
let mut functions = Default::default();
|
||||||
let mut type_iterators = HashMap::with_capacity(16);
|
let mut type_iterators = Default::default();
|
||||||
|
|
||||||
path.push("root");
|
path.push("root");
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
boxed::Box,
|
boxed::Box,
|
||||||
collections::HashMap,
|
collections::BTreeMap,
|
||||||
io::Error as IoError,
|
io::Error as IoError,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
string::String,
|
string::String,
|
||||||
@ -44,9 +44,9 @@ pub struct FileModuleResolver {
|
|||||||
cache_enabled: bool,
|
cache_enabled: bool,
|
||||||
|
|
||||||
#[cfg(not(feature = "sync"))]
|
#[cfg(not(feature = "sync"))]
|
||||||
cache: crate::stdlib::cell::RefCell<HashMap<PathBuf, Shared<Module>>>,
|
cache: crate::stdlib::cell::RefCell<BTreeMap<PathBuf, Shared<Module>>>,
|
||||||
#[cfg(feature = "sync")]
|
#[cfg(feature = "sync")]
|
||||||
cache: crate::stdlib::sync::RwLock<HashMap<PathBuf, Shared<Module>>>,
|
cache: crate::stdlib::sync::RwLock<BTreeMap<PathBuf, Shared<Module>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for FileModuleResolver {
|
impl Default for FileModuleResolver {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::stdlib::{boxed::Box, collections::HashMap, ops::AddAssign, string::String};
|
use crate::stdlib::{boxed::Box, collections::BTreeMap, ops::AddAssign, string::String};
|
||||||
use crate::{Engine, EvalAltResult, Module, ModuleResolver, Position, Shared};
|
use crate::{Engine, EvalAltResult, Module, ModuleResolver, Position, Shared};
|
||||||
|
|
||||||
/// A static [module][Module] resolution service that serves [modules][Module] added into it.
|
/// A static [module][Module] resolution service that serves [modules][Module] added into it.
|
||||||
@ -19,7 +19,7 @@ use crate::{Engine, EvalAltResult, Module, ModuleResolver, Position, Shared};
|
|||||||
/// engine.set_module_resolver(resolver);
|
/// engine.set_module_resolver(resolver);
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct StaticModuleResolver(HashMap<String, Shared<Module>>);
|
pub struct StaticModuleResolver(BTreeMap<String, Shared<Module>>);
|
||||||
|
|
||||||
impl StaticModuleResolver {
|
impl StaticModuleResolver {
|
||||||
/// Create a new [`StaticModuleResolver`].
|
/// Create a new [`StaticModuleResolver`].
|
||||||
|
@ -24,91 +24,91 @@ macro_rules! gen_arithmetic_functions {
|
|||||||
#[export_module]
|
#[export_module]
|
||||||
pub mod functions {
|
pub mod functions {
|
||||||
#[rhai_fn(name = "+", return_raw)]
|
#[rhai_fn(name = "+", return_raw)]
|
||||||
pub fn add(x: $arg_type, y: $arg_type) -> Result<Dynamic, Box<EvalAltResult>> {
|
pub fn add(x: $arg_type, y: $arg_type) -> Result<$arg_type, Box<EvalAltResult>> {
|
||||||
if cfg!(not(feature = "unchecked")) {
|
if cfg!(not(feature = "unchecked")) {
|
||||||
x.checked_add(y).ok_or_else(|| make_err(format!("Addition overflow: {} + {}", x, y))).map(Dynamic::from)
|
x.checked_add(y).ok_or_else(|| make_err(format!("Addition overflow: {} + {}", x, y)))
|
||||||
} else {
|
} else {
|
||||||
Ok(Dynamic::from(x + y))
|
Ok(x + y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "-", return_raw)]
|
#[rhai_fn(name = "-", return_raw)]
|
||||||
pub fn subtract(x: $arg_type, y: $arg_type) -> Result<Dynamic, Box<EvalAltResult>> {
|
pub fn subtract(x: $arg_type, y: $arg_type) -> Result<$arg_type, Box<EvalAltResult>> {
|
||||||
if cfg!(not(feature = "unchecked")) {
|
if cfg!(not(feature = "unchecked")) {
|
||||||
x.checked_sub(y).ok_or_else(|| make_err(format!("Subtraction overflow: {} - {}", x, y))).map(Dynamic::from)
|
x.checked_sub(y).ok_or_else(|| make_err(format!("Subtraction overflow: {} - {}", x, y)))
|
||||||
} else {
|
} else {
|
||||||
Ok(Dynamic::from(x - y))
|
Ok(x - y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "*", return_raw)]
|
#[rhai_fn(name = "*", return_raw)]
|
||||||
pub fn multiply(x: $arg_type, y: $arg_type) -> Result<Dynamic, Box<EvalAltResult>> {
|
pub fn multiply(x: $arg_type, y: $arg_type) -> Result<$arg_type, Box<EvalAltResult>> {
|
||||||
if cfg!(not(feature = "unchecked")) {
|
if cfg!(not(feature = "unchecked")) {
|
||||||
x.checked_mul(y).ok_or_else(|| make_err(format!("Multiplication overflow: {} * {}", x, y))).map(Dynamic::from)
|
x.checked_mul(y).ok_or_else(|| make_err(format!("Multiplication overflow: {} * {}", x, y)))
|
||||||
} else {
|
} else {
|
||||||
Ok(Dynamic::from(x * y))
|
Ok(x * y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "/", return_raw)]
|
#[rhai_fn(name = "/", return_raw)]
|
||||||
pub fn divide(x: $arg_type, y: $arg_type) -> Result<Dynamic, Box<EvalAltResult>> {
|
pub fn divide(x: $arg_type, y: $arg_type) -> Result<$arg_type, Box<EvalAltResult>> {
|
||||||
if cfg!(not(feature = "unchecked")) {
|
if cfg!(not(feature = "unchecked")) {
|
||||||
// Detect division by zero
|
// Detect division by zero
|
||||||
if y == 0 {
|
if y == 0 {
|
||||||
Err(make_err(format!("Division by zero: {} / {}", x, y)))
|
Err(make_err(format!("Division by zero: {} / {}", x, y)))
|
||||||
} else {
|
} else {
|
||||||
x.checked_div(y).ok_or_else(|| make_err(format!("Division overflow: {} / {}", x, y))).map(Dynamic::from)
|
x.checked_div(y).ok_or_else(|| make_err(format!("Division overflow: {} / {}", x, y)))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Ok(Dynamic::from(x / y))
|
Ok(x / y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "%", return_raw)]
|
#[rhai_fn(name = "%", return_raw)]
|
||||||
pub fn modulo(x: $arg_type, y: $arg_type) -> Result<Dynamic, Box<EvalAltResult>> {
|
pub fn modulo(x: $arg_type, y: $arg_type) -> Result<$arg_type, Box<EvalAltResult>> {
|
||||||
if cfg!(not(feature = "unchecked")) {
|
if cfg!(not(feature = "unchecked")) {
|
||||||
x.checked_rem(y).ok_or_else(|| make_err(format!("Modulo division by zero or overflow: {} % {}", x, y))).map(Dynamic::from)
|
x.checked_rem(y).ok_or_else(|| make_err(format!("Modulo division by zero or overflow: {} % {}", x, y)))
|
||||||
} else {
|
} else {
|
||||||
Ok(Dynamic::from(x % y))
|
Ok(x % y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "**", return_raw)]
|
#[rhai_fn(name = "**", return_raw)]
|
||||||
pub fn power(x: INT, y: INT) -> Result<Dynamic, Box<EvalAltResult>> {
|
pub fn power(x: $arg_type, y: INT) -> Result<$arg_type, Box<EvalAltResult>> {
|
||||||
if cfg!(not(feature = "unchecked")) {
|
if cfg!(not(feature = "unchecked")) {
|
||||||
if cfg!(not(feature = "only_i32")) && y > (u32::MAX as INT) {
|
if cfg!(not(feature = "only_i32")) && y > (u32::MAX as INT) {
|
||||||
Err(make_err(format!("Integer raised to too large an index: {} ~ {}", x, y)))
|
Err(make_err(format!("Integer raised to too large an index: {} ~ {}", x, y)))
|
||||||
} else if y < 0 {
|
} else if y < 0 {
|
||||||
Err(make_err(format!("Integer raised to a negative index: {} ~ {}", x, y)))
|
Err(make_err(format!("Integer raised to a negative index: {} ~ {}", x, y)))
|
||||||
} else {
|
} else {
|
||||||
x.checked_pow(y as u32).ok_or_else(|| make_err(format!("Power overflow: {} ~ {}", x, y))).map(Dynamic::from)
|
x.checked_pow(y as u32).ok_or_else(|| make_err(format!("Power overflow: {} ~ {}", x, y)))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Ok(Dynamic::from(x.pow(y as u32)))
|
Ok(x.pow(y as u32))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rhai_fn(name = "<<", return_raw)]
|
#[rhai_fn(name = "<<", return_raw)]
|
||||||
pub fn shift_left(x: $arg_type, y: INT) -> Result<Dynamic, Box<EvalAltResult>> {
|
pub fn shift_left(x: $arg_type, y: INT) -> Result<$arg_type, Box<EvalAltResult>> {
|
||||||
if cfg!(not(feature = "unchecked")) {
|
if cfg!(not(feature = "unchecked")) {
|
||||||
if cfg!(not(feature = "only_i32")) && y > (u32::MAX as INT) {
|
if cfg!(not(feature = "only_i32")) && y > (u32::MAX as INT) {
|
||||||
Err(make_err(format!("Left-shift by too many bits: {} << {}", x, y)))
|
Err(make_err(format!("Left-shift by too many bits: {} << {}", x, y)))
|
||||||
} else if y < 0 {
|
} else if y < 0 {
|
||||||
Err(make_err(format!("Left-shift by a negative number: {} << {}", x, y)))
|
Err(make_err(format!("Left-shift by a negative number: {} << {}", x, y)))
|
||||||
} else {
|
} else {
|
||||||
x.checked_shl(y as u32).ok_or_else(|| make_err(format!("Left-shift by too many bits: {} << {}", x, y))).map(Dynamic::from)
|
x.checked_shl(y as u32).ok_or_else(|| make_err(format!("Left-shift by too many bits: {} << {}", x, y)))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Ok(Dynamic::from(x << y))
|
Ok(x << y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = ">>", return_raw)]
|
#[rhai_fn(name = ">>", return_raw)]
|
||||||
pub fn shift_right(x: $arg_type, y: INT) -> Result<Dynamic, Box<EvalAltResult>> {
|
pub fn shift_right(x: $arg_type, y: INT) -> Result<$arg_type, Box<EvalAltResult>> {
|
||||||
if cfg!(not(feature = "unchecked")) {
|
if cfg!(not(feature = "unchecked")) {
|
||||||
if cfg!(not(feature = "only_i32")) && y > (u32::MAX as INT) {
|
if cfg!(not(feature = "only_i32")) && y > (u32::MAX as INT) {
|
||||||
Err(make_err(format!("Right-shift by too many bits: {} >> {}", x, y)))
|
Err(make_err(format!("Right-shift by too many bits: {} >> {}", x, y)))
|
||||||
} else if y < 0 {
|
} else if y < 0 {
|
||||||
Err(make_err(format!("Right-shift by a negative number: {} >> {}", x, y)))
|
Err(make_err(format!("Right-shift by a negative number: {} >> {}", x, y)))
|
||||||
} else {
|
} else {
|
||||||
x.checked_shr(y as u32).ok_or_else(|| make_err(format!("Right-shift by too many bits: {} >> {}", x, y))).map(Dynamic::from)
|
x.checked_shr(y as u32).ok_or_else(|| make_err(format!("Right-shift by too many bits: {} >> {}", x, y)))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Ok(Dynamic::from(x >> y))
|
Ok(x >> y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "&")]
|
#[rhai_fn(name = "&")]
|
||||||
@ -136,11 +136,11 @@ macro_rules! gen_signed_functions {
|
|||||||
#[export_module]
|
#[export_module]
|
||||||
pub mod functions {
|
pub mod functions {
|
||||||
#[rhai_fn(name = "-", return_raw)]
|
#[rhai_fn(name = "-", return_raw)]
|
||||||
pub fn neg(x: $arg_type) -> Result<Dynamic, Box<EvalAltResult>> {
|
pub fn neg(x: $arg_type) -> Result<$arg_type, Box<EvalAltResult>> {
|
||||||
if cfg!(not(feature = "unchecked")) {
|
if cfg!(not(feature = "unchecked")) {
|
||||||
x.checked_neg().ok_or_else(|| make_err(format!("Negation overflow: -{}", x))).map(Dynamic::from)
|
x.checked_neg().ok_or_else(|| make_err(format!("Negation overflow: -{}", x)))
|
||||||
} else {
|
} else {
|
||||||
Ok(Dynamic::from(-x))
|
Ok(-x)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "+")]
|
#[rhai_fn(name = "+")]
|
||||||
@ -148,11 +148,11 @@ macro_rules! gen_signed_functions {
|
|||||||
x
|
x
|
||||||
}
|
}
|
||||||
#[rhai_fn(return_raw)]
|
#[rhai_fn(return_raw)]
|
||||||
pub fn abs(x: $arg_type) -> Result<Dynamic, Box<EvalAltResult>> {
|
pub fn abs(x: $arg_type) -> Result<$arg_type, Box<EvalAltResult>> {
|
||||||
if cfg!(not(feature = "unchecked")) {
|
if cfg!(not(feature = "unchecked")) {
|
||||||
x.checked_abs().ok_or_else(|| make_err(format!("Negation overflow: -{}", x))).map(Dynamic::from)
|
x.checked_abs().ok_or_else(|| make_err(format!("Negation overflow: -{}", x)))
|
||||||
} else {
|
} else {
|
||||||
Ok(Dynamic::from(x.abs()))
|
Ok(x.abs())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn sign(x: $arg_type) -> INT {
|
pub fn sign(x: $arg_type) -> INT {
|
||||||
@ -318,14 +318,14 @@ mod f32_functions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "**", return_raw)]
|
#[rhai_fn(name = "**", return_raw)]
|
||||||
pub fn pow_f_i(x: f32, y: INT) -> Result<Dynamic, Box<EvalAltResult>> {
|
pub fn pow_f_i(x: f32, y: INT) -> Result<f32, Box<EvalAltResult>> {
|
||||||
if cfg!(not(feature = "unchecked")) && y > (i32::MAX as INT) {
|
if cfg!(not(feature = "unchecked")) && y > (i32::MAX as INT) {
|
||||||
Err(make_err(format!(
|
Err(make_err(format!(
|
||||||
"Number raised to too large an index: {} ~ {}",
|
"Number raised to too large an index: {} ~ {}",
|
||||||
x, y
|
x, y
|
||||||
)))
|
)))
|
||||||
} else {
|
} else {
|
||||||
Ok(Dynamic::from(x.powi(y as i32)))
|
Ok(x.powi(y as i32))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -423,14 +423,14 @@ mod f64_functions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "**", return_raw)]
|
#[rhai_fn(name = "**", return_raw)]
|
||||||
pub fn pow_f_i(x: FLOAT, y: INT) -> Result<Dynamic, Box<EvalAltResult>> {
|
pub fn pow_f_i(x: FLOAT, y: INT) -> Result<FLOAT, Box<EvalAltResult>> {
|
||||||
if cfg!(not(feature = "unchecked")) && y > (i32::MAX as INT) {
|
if cfg!(not(feature = "unchecked")) && y > (i32::MAX as INT) {
|
||||||
Err(make_err(format!(
|
Err(make_err(format!(
|
||||||
"Number raised to too large an index: {} ~ {}",
|
"Number raised to too large an index: {} ~ {}",
|
||||||
x, y
|
x, y
|
||||||
)))
|
)))
|
||||||
} else {
|
} else {
|
||||||
Ok(x.powi(y as i32).into())
|
Ok(x.powi(y as i32))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -441,37 +441,34 @@ pub mod decimal_functions {
|
|||||||
use rust_decimal::{prelude::Zero, Decimal};
|
use rust_decimal::{prelude::Zero, Decimal};
|
||||||
|
|
||||||
#[rhai_fn(skip, return_raw)]
|
#[rhai_fn(skip, return_raw)]
|
||||||
pub fn add(x: Decimal, y: Decimal) -> Result<Dynamic, Box<EvalAltResult>> {
|
pub fn add(x: Decimal, y: Decimal) -> Result<Decimal, Box<EvalAltResult>> {
|
||||||
if cfg!(not(feature = "unchecked")) {
|
if cfg!(not(feature = "unchecked")) {
|
||||||
x.checked_add(y)
|
x.checked_add(y)
|
||||||
.ok_or_else(|| make_err(format!("Addition overflow: {} + {}", x, y)))
|
.ok_or_else(|| make_err(format!("Addition overflow: {} + {}", x, y)))
|
||||||
.map(Into::<Dynamic>::into)
|
|
||||||
} else {
|
} else {
|
||||||
Ok(Dynamic::from(x + y))
|
Ok(x + y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[rhai_fn(skip, return_raw)]
|
#[rhai_fn(skip, return_raw)]
|
||||||
pub fn subtract(x: Decimal, y: Decimal) -> Result<Dynamic, Box<EvalAltResult>> {
|
pub fn subtract(x: Decimal, y: Decimal) -> Result<Decimal, Box<EvalAltResult>> {
|
||||||
if cfg!(not(feature = "unchecked")) {
|
if cfg!(not(feature = "unchecked")) {
|
||||||
x.checked_sub(y)
|
x.checked_sub(y)
|
||||||
.ok_or_else(|| make_err(format!("Subtraction overflow: {} - {}", x, y)))
|
.ok_or_else(|| make_err(format!("Subtraction overflow: {} - {}", x, y)))
|
||||||
.map(Into::<Dynamic>::into)
|
|
||||||
} else {
|
} else {
|
||||||
Ok(Dynamic::from(x - y))
|
Ok(x - y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[rhai_fn(skip, return_raw)]
|
#[rhai_fn(skip, return_raw)]
|
||||||
pub fn multiply(x: Decimal, y: Decimal) -> Result<Dynamic, Box<EvalAltResult>> {
|
pub fn multiply(x: Decimal, y: Decimal) -> Result<Decimal, Box<EvalAltResult>> {
|
||||||
if cfg!(not(feature = "unchecked")) {
|
if cfg!(not(feature = "unchecked")) {
|
||||||
x.checked_mul(y)
|
x.checked_mul(y)
|
||||||
.ok_or_else(|| make_err(format!("Multiplication overflow: {} * {}", x, y)))
|
.ok_or_else(|| make_err(format!("Multiplication overflow: {} * {}", x, y)))
|
||||||
.map(Into::<Dynamic>::into)
|
|
||||||
} else {
|
} else {
|
||||||
Ok(Dynamic::from(x * y))
|
Ok(x * y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[rhai_fn(skip, return_raw)]
|
#[rhai_fn(skip, return_raw)]
|
||||||
pub fn divide(x: Decimal, y: Decimal) -> Result<Dynamic, Box<EvalAltResult>> {
|
pub fn divide(x: Decimal, y: Decimal) -> Result<Decimal, Box<EvalAltResult>> {
|
||||||
if cfg!(not(feature = "unchecked")) {
|
if cfg!(not(feature = "unchecked")) {
|
||||||
// Detect division by zero
|
// Detect division by zero
|
||||||
if y == Decimal::zero() {
|
if y == Decimal::zero() {
|
||||||
@ -479,25 +476,22 @@ pub mod decimal_functions {
|
|||||||
} else {
|
} else {
|
||||||
x.checked_div(y)
|
x.checked_div(y)
|
||||||
.ok_or_else(|| make_err(format!("Division overflow: {} / {}", x, y)))
|
.ok_or_else(|| make_err(format!("Division overflow: {} / {}", x, y)))
|
||||||
.map(Into::<Dynamic>::into)
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Ok(Dynamic::from(x / y))
|
Ok(x / y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[rhai_fn(skip, return_raw)]
|
#[rhai_fn(skip, return_raw)]
|
||||||
pub fn modulo(x: Decimal, y: Decimal) -> Result<Dynamic, Box<EvalAltResult>> {
|
pub fn modulo(x: Decimal, y: Decimal) -> Result<Decimal, Box<EvalAltResult>> {
|
||||||
if cfg!(not(feature = "unchecked")) {
|
if cfg!(not(feature = "unchecked")) {
|
||||||
x.checked_rem(y)
|
x.checked_rem(y).ok_or_else(|| {
|
||||||
.ok_or_else(|| {
|
|
||||||
make_err(format!(
|
make_err(format!(
|
||||||
"Modulo division by zero or overflow: {} % {}",
|
"Modulo division by zero or overflow: {} % {}",
|
||||||
x, y
|
x, y
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
.map(Into::<Dynamic>::into)
|
|
||||||
} else {
|
} else {
|
||||||
Ok(Dynamic::from(x % y))
|
Ok(x % y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "-")]
|
#[rhai_fn(name = "-")]
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
#![cfg(not(feature = "no_index"))]
|
#![cfg(not(feature = "no_index"))]
|
||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
use crate::engine::{OP_EQUALS, TYPICAL_ARRAY_SIZE};
|
use crate::engine::OP_EQUALS;
|
||||||
use crate::plugin::*;
|
use crate::plugin::*;
|
||||||
use crate::stdlib::{any::TypeId, boxed::Box, cmp::max, cmp::Ordering, mem, string::ToString};
|
use crate::stdlib::{any::TypeId, boxed::Box, cmp::Ordering, mem, string::ToString};
|
||||||
use crate::{def_package, Array, Dynamic, EvalAltResult, FnPtr, NativeCallContext, Position, INT};
|
use crate::{def_package, Array, Dynamic, EvalAltResult, FnPtr, NativeCallContext, Position, INT};
|
||||||
|
|
||||||
def_package!(crate:BasicArrayPackage:"Basic array utilities.", lib, {
|
def_package!(crate:BasicArrayPackage:"Basic array utilities.", lib, {
|
||||||
@ -47,7 +47,7 @@ mod array_functions {
|
|||||||
array: &mut Array,
|
array: &mut Array,
|
||||||
len: INT,
|
len: INT,
|
||||||
item: Dynamic,
|
item: Dynamic,
|
||||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
) -> Result<(), Box<EvalAltResult>> {
|
||||||
// Check if array will be over max size limit
|
// Check if array will be over max size limit
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
if _ctx.engine().max_array_size() > 0
|
if _ctx.engine().max_array_size() > 0
|
||||||
@ -62,7 +62,7 @@ mod array_functions {
|
|||||||
array.resize(len as usize, item);
|
array.resize(len as usize, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Dynamic::UNIT)
|
Ok(())
|
||||||
}
|
}
|
||||||
pub fn pop(array: &mut Array) -> Dynamic {
|
pub fn pop(array: &mut Array) -> Dynamic {
|
||||||
array.pop().unwrap_or_else(|| ().into())
|
array.pop().unwrap_or_else(|| ().into())
|
||||||
@ -169,8 +169,8 @@ mod array_functions {
|
|||||||
ctx: NativeCallContext,
|
ctx: NativeCallContext,
|
||||||
array: &mut Array,
|
array: &mut Array,
|
||||||
mapper: FnPtr,
|
mapper: FnPtr,
|
||||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
) -> Result<Array, Box<EvalAltResult>> {
|
||||||
let mut ar = Array::with_capacity(max(TYPICAL_ARRAY_SIZE, array.len()));
|
let mut ar = Array::with_capacity(array.len());
|
||||||
|
|
||||||
for (i, item) in array.iter().enumerate() {
|
for (i, item) in array.iter().enumerate() {
|
||||||
ar.push(
|
ar.push(
|
||||||
@ -195,15 +195,15 @@ mod array_functions {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(ar.into())
|
Ok(ar)
|
||||||
}
|
}
|
||||||
#[rhai_fn(return_raw, pure)]
|
#[rhai_fn(return_raw, pure)]
|
||||||
pub fn filter(
|
pub fn filter(
|
||||||
ctx: NativeCallContext,
|
ctx: NativeCallContext,
|
||||||
array: &mut Array,
|
array: &mut Array,
|
||||||
filter: FnPtr,
|
filter: FnPtr,
|
||||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
) -> Result<Array, Box<EvalAltResult>> {
|
||||||
let mut ar = Array::with_capacity(max(TYPICAL_ARRAY_SIZE, array.len()));
|
let mut ar = Array::new();
|
||||||
|
|
||||||
for (i, item) in array.iter().enumerate() {
|
for (i, item) in array.iter().enumerate() {
|
||||||
if filter
|
if filter
|
||||||
@ -231,14 +231,14 @@ mod array_functions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(ar.into())
|
Ok(ar)
|
||||||
}
|
}
|
||||||
#[rhai_fn(return_raw, pure)]
|
#[rhai_fn(return_raw, pure)]
|
||||||
pub fn contains(
|
pub fn contains(
|
||||||
ctx: NativeCallContext,
|
ctx: NativeCallContext,
|
||||||
array: &mut Array,
|
array: &mut Array,
|
||||||
value: Dynamic,
|
value: Dynamic,
|
||||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
) -> Result<bool, Box<EvalAltResult>> {
|
||||||
for item in array.iter_mut() {
|
for item in array.iter_mut() {
|
||||||
if ctx
|
if ctx
|
||||||
.call_fn_dynamic_raw(OP_EQUALS, true, &mut [item, &mut value.clone()])
|
.call_fn_dynamic_raw(OP_EQUALS, true, &mut [item, &mut value.clone()])
|
||||||
@ -258,18 +258,18 @@ mod array_functions {
|
|||||||
.as_bool()
|
.as_bool()
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
{
|
{
|
||||||
return Ok(Dynamic::TRUE);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Dynamic::FALSE)
|
Ok(false)
|
||||||
}
|
}
|
||||||
#[rhai_fn(return_raw, pure)]
|
#[rhai_fn(return_raw, pure)]
|
||||||
pub fn index_of(
|
pub fn index_of(
|
||||||
ctx: NativeCallContext,
|
ctx: NativeCallContext,
|
||||||
array: &mut Array,
|
array: &mut Array,
|
||||||
value: Dynamic,
|
value: Dynamic,
|
||||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
) -> Result<INT, Box<EvalAltResult>> {
|
||||||
for (i, item) in array.iter_mut().enumerate() {
|
for (i, item) in array.iter_mut().enumerate() {
|
||||||
if ctx
|
if ctx
|
||||||
.call_fn_dynamic_raw(OP_EQUALS, true, &mut [item, &mut value.clone()])
|
.call_fn_dynamic_raw(OP_EQUALS, true, &mut [item, &mut value.clone()])
|
||||||
@ -289,18 +289,18 @@ mod array_functions {
|
|||||||
.as_bool()
|
.as_bool()
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
{
|
{
|
||||||
return Ok((i as INT).into());
|
return Ok(i as INT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((-1 as INT).into())
|
Ok(-1 as INT)
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "index_of", return_raw, pure)]
|
#[rhai_fn(name = "index_of", return_raw, pure)]
|
||||||
pub fn index_of_filter(
|
pub fn index_of_filter(
|
||||||
ctx: NativeCallContext,
|
ctx: NativeCallContext,
|
||||||
array: &mut Array,
|
array: &mut Array,
|
||||||
filter: FnPtr,
|
filter: FnPtr,
|
||||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
) -> Result<INT, Box<EvalAltResult>> {
|
||||||
for (i, item) in array.iter().enumerate() {
|
for (i, item) in array.iter().enumerate() {
|
||||||
if filter
|
if filter
|
||||||
.call_dynamic(&ctx, None, [item.clone()])
|
.call_dynamic(&ctx, None, [item.clone()])
|
||||||
@ -323,18 +323,18 @@ mod array_functions {
|
|||||||
.as_bool()
|
.as_bool()
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
{
|
{
|
||||||
return Ok((i as INT).into());
|
return Ok(i as INT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((-1 as INT).into())
|
Ok(-1 as INT)
|
||||||
}
|
}
|
||||||
#[rhai_fn(return_raw, pure)]
|
#[rhai_fn(return_raw, pure)]
|
||||||
pub fn some(
|
pub fn some(
|
||||||
ctx: NativeCallContext,
|
ctx: NativeCallContext,
|
||||||
array: &mut Array,
|
array: &mut Array,
|
||||||
filter: FnPtr,
|
filter: FnPtr,
|
||||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
) -> Result<bool, Box<EvalAltResult>> {
|
||||||
for (i, item) in array.iter().enumerate() {
|
for (i, item) in array.iter().enumerate() {
|
||||||
if filter
|
if filter
|
||||||
.call_dynamic(&ctx, None, [item.clone()])
|
.call_dynamic(&ctx, None, [item.clone()])
|
||||||
@ -357,18 +357,18 @@ mod array_functions {
|
|||||||
.as_bool()
|
.as_bool()
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
{
|
{
|
||||||
return Ok(true.into());
|
return Ok(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(false.into())
|
Ok(false)
|
||||||
}
|
}
|
||||||
#[rhai_fn(return_raw, pure)]
|
#[rhai_fn(return_raw, pure)]
|
||||||
pub fn all(
|
pub fn all(
|
||||||
ctx: NativeCallContext,
|
ctx: NativeCallContext,
|
||||||
array: &mut Array,
|
array: &mut Array,
|
||||||
filter: FnPtr,
|
filter: FnPtr,
|
||||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
) -> Result<bool, Box<EvalAltResult>> {
|
||||||
for (i, item) in array.iter().enumerate() {
|
for (i, item) in array.iter().enumerate() {
|
||||||
if !filter
|
if !filter
|
||||||
.call_dynamic(&ctx, None, [item.clone()])
|
.call_dynamic(&ctx, None, [item.clone()])
|
||||||
@ -391,11 +391,11 @@ mod array_functions {
|
|||||||
.as_bool()
|
.as_bool()
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
{
|
{
|
||||||
return Ok(false.into());
|
return Ok(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(true.into())
|
Ok(true)
|
||||||
}
|
}
|
||||||
#[rhai_fn(return_raw, pure)]
|
#[rhai_fn(return_raw, pure)]
|
||||||
pub fn reduce(
|
pub fn reduce(
|
||||||
@ -403,7 +403,7 @@ mod array_functions {
|
|||||||
array: &mut Array,
|
array: &mut Array,
|
||||||
reducer: FnPtr,
|
reducer: FnPtr,
|
||||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
let mut result: Dynamic = Dynamic::UNIT;
|
let mut result = Dynamic::UNIT;
|
||||||
|
|
||||||
for (i, item) in array.iter().enumerate() {
|
for (i, item) in array.iter().enumerate() {
|
||||||
result = reducer
|
result = reducer
|
||||||
@ -433,16 +433,9 @@ mod array_functions {
|
|||||||
ctx: NativeCallContext,
|
ctx: NativeCallContext,
|
||||||
array: &mut Array,
|
array: &mut Array,
|
||||||
reducer: FnPtr,
|
reducer: FnPtr,
|
||||||
initial: FnPtr,
|
initial: Dynamic,
|
||||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
let mut result = initial.call_dynamic(&ctx, None, []).map_err(|err| {
|
let mut result = initial;
|
||||||
Box::new(EvalAltResult::ErrorInFunctionCall(
|
|
||||||
"reduce".to_string(),
|
|
||||||
ctx.source().unwrap_or("").to_string(),
|
|
||||||
err,
|
|
||||||
Position::NONE,
|
|
||||||
))
|
|
||||||
})?;
|
|
||||||
|
|
||||||
for (i, item) in array.iter().enumerate() {
|
for (i, item) in array.iter().enumerate() {
|
||||||
result = reducer
|
result = reducer
|
||||||
@ -473,7 +466,7 @@ mod array_functions {
|
|||||||
array: &mut Array,
|
array: &mut Array,
|
||||||
reducer: FnPtr,
|
reducer: FnPtr,
|
||||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
let mut result: Dynamic = Dynamic::UNIT;
|
let mut result = Dynamic::UNIT;
|
||||||
|
|
||||||
for (i, item) in array.iter().enumerate().rev() {
|
for (i, item) in array.iter().enumerate().rev() {
|
||||||
result = reducer
|
result = reducer
|
||||||
@ -503,16 +496,9 @@ mod array_functions {
|
|||||||
ctx: NativeCallContext,
|
ctx: NativeCallContext,
|
||||||
array: &mut Array,
|
array: &mut Array,
|
||||||
reducer: FnPtr,
|
reducer: FnPtr,
|
||||||
initial: FnPtr,
|
initial: Dynamic,
|
||||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
let mut result = initial.call_dynamic(&ctx, None, []).map_err(|err| {
|
let mut result = initial;
|
||||||
Box::new(EvalAltResult::ErrorInFunctionCall(
|
|
||||||
"reduce_rev".to_string(),
|
|
||||||
ctx.source().unwrap_or("").to_string(),
|
|
||||||
err,
|
|
||||||
Position::NONE,
|
|
||||||
))
|
|
||||||
})?;
|
|
||||||
|
|
||||||
for (i, item) in array.iter().enumerate().rev() {
|
for (i, item) in array.iter().enumerate().rev() {
|
||||||
result = reducer
|
result = reducer
|
||||||
@ -542,7 +528,7 @@ mod array_functions {
|
|||||||
ctx: NativeCallContext,
|
ctx: NativeCallContext,
|
||||||
array: &mut Array,
|
array: &mut Array,
|
||||||
comparer: FnPtr,
|
comparer: FnPtr,
|
||||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
) -> Result<(), Box<EvalAltResult>> {
|
||||||
array.sort_by(|x, y| {
|
array.sort_by(|x, y| {
|
||||||
comparer
|
comparer
|
||||||
.call_dynamic(&ctx, None, [x.clone(), y.clone()])
|
.call_dynamic(&ctx, None, [x.clone(), y.clone()])
|
||||||
@ -571,15 +557,15 @@ mod array_functions {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(Dynamic::UNIT)
|
Ok(())
|
||||||
}
|
}
|
||||||
#[rhai_fn(return_raw)]
|
#[rhai_fn(return_raw)]
|
||||||
pub fn drain(
|
pub fn drain(
|
||||||
ctx: NativeCallContext,
|
ctx: NativeCallContext,
|
||||||
array: &mut Array,
|
array: &mut Array,
|
||||||
filter: FnPtr,
|
filter: FnPtr,
|
||||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
) -> Result<Array, Box<EvalAltResult>> {
|
||||||
let mut drained = Array::with_capacity(max(TYPICAL_ARRAY_SIZE, array.len()));
|
let mut drained = Array::with_capacity(array.len());
|
||||||
|
|
||||||
let mut i = array.len();
|
let mut i = array.len();
|
||||||
|
|
||||||
@ -611,7 +597,7 @@ mod array_functions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(drained.into())
|
Ok(drained)
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "drain")]
|
#[rhai_fn(name = "drain")]
|
||||||
pub fn drain_range(array: &mut Array, start: INT, len: INT) -> Array {
|
pub fn drain_range(array: &mut Array, start: INT, len: INT) -> Array {
|
||||||
@ -638,8 +624,8 @@ mod array_functions {
|
|||||||
ctx: NativeCallContext,
|
ctx: NativeCallContext,
|
||||||
array: &mut Array,
|
array: &mut Array,
|
||||||
filter: FnPtr,
|
filter: FnPtr,
|
||||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
) -> Result<Array, Box<EvalAltResult>> {
|
||||||
let mut drained = Array::with_capacity(max(TYPICAL_ARRAY_SIZE, array.len()));
|
let mut drained = Array::new();
|
||||||
|
|
||||||
let mut i = array.len();
|
let mut i = array.len();
|
||||||
|
|
||||||
@ -671,7 +657,7 @@ mod array_functions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(drained.into())
|
Ok(drained)
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "retain")]
|
#[rhai_fn(name = "retain")]
|
||||||
pub fn retain_range(array: &mut Array, start: INT, len: INT) -> Array {
|
pub fn retain_range(array: &mut Array, start: INT, len: INT) -> Array {
|
||||||
@ -701,12 +687,12 @@ mod array_functions {
|
|||||||
ctx: NativeCallContext,
|
ctx: NativeCallContext,
|
||||||
array: &mut Array,
|
array: &mut Array,
|
||||||
mut array2: Array,
|
mut array2: Array,
|
||||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
) -> Result<bool, Box<EvalAltResult>> {
|
||||||
if array.len() != array2.len() {
|
if array.len() != array2.len() {
|
||||||
return Ok(false.into());
|
return Ok(false);
|
||||||
}
|
}
|
||||||
if array.is_empty() {
|
if array.is_empty() {
|
||||||
return Ok(true.into());
|
return Ok(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (a1, a2) in array.iter_mut().zip(array2.iter_mut()) {
|
for (a1, a2) in array.iter_mut().zip(array2.iter_mut()) {
|
||||||
@ -728,18 +714,18 @@ mod array_functions {
|
|||||||
.as_bool()
|
.as_bool()
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
{
|
{
|
||||||
return Ok(Dynamic::FALSE);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Dynamic::TRUE)
|
Ok(true)
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "!=", return_raw, pure)]
|
#[rhai_fn(name = "!=", return_raw, pure)]
|
||||||
pub fn not_equals(
|
pub fn not_equals(
|
||||||
ctx: NativeCallContext,
|
ctx: NativeCallContext,
|
||||||
array: &mut Array,
|
array: &mut Array,
|
||||||
array2: Array,
|
array2: Array,
|
||||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
) -> Result<bool, Box<EvalAltResult>> {
|
||||||
equals(ctx, array, array2).map(|r| (!r.as_bool().unwrap()).into())
|
equals(ctx, array, array2).map(|r| !r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,34 +34,34 @@ mod fn_ptr_functions {
|
|||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
fn collect_fn_metadata(ctx: NativeCallContext) -> crate::Array {
|
fn collect_fn_metadata(ctx: NativeCallContext) -> crate::Array {
|
||||||
use crate::{ast::ScriptFnDef, stdlib::collections::HashMap, Array, Map};
|
use crate::{ast::ScriptFnDef, stdlib::collections::BTreeSet, Array, Map};
|
||||||
|
|
||||||
// Create a metadata record for a function.
|
// Create a metadata record for a function.
|
||||||
fn make_metadata(
|
fn make_metadata(
|
||||||
dict: &HashMap<&str, ImmutableString>,
|
dict: &BTreeSet<ImmutableString>,
|
||||||
namespace: Option<ImmutableString>,
|
namespace: Option<ImmutableString>,
|
||||||
f: &ScriptFnDef,
|
f: &ScriptFnDef,
|
||||||
) -> Map {
|
) -> Map {
|
||||||
let mut map = Map::with_capacity(6);
|
let mut map = Map::new();
|
||||||
|
|
||||||
if let Some(ns) = namespace {
|
if let Some(ns) = namespace {
|
||||||
map.insert(dict["namespace"].clone(), ns.into());
|
map.insert(dict.get("namespace").unwrap().clone(), ns.into());
|
||||||
}
|
}
|
||||||
map.insert(dict["name"].clone(), f.name.clone().into());
|
map.insert(dict.get("name").unwrap().clone(), f.name.clone().into());
|
||||||
map.insert(
|
map.insert(
|
||||||
dict["access"].clone(),
|
dict.get("access").unwrap().clone(),
|
||||||
match f.access {
|
match f.access {
|
||||||
FnAccess::Public => dict["public"].clone(),
|
FnAccess::Public => dict.get("public").unwrap().clone(),
|
||||||
FnAccess::Private => dict["private"].clone(),
|
FnAccess::Private => dict.get("private").unwrap().clone(),
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
map.insert(
|
map.insert(
|
||||||
dict["is_anonymous"].clone(),
|
dict.get("is_anonymous").unwrap().clone(),
|
||||||
f.name.starts_with(crate::engine::FN_ANONYMOUS).into(),
|
f.name.starts_with(crate::engine::FN_ANONYMOUS).into(),
|
||||||
);
|
);
|
||||||
map.insert(
|
map.insert(
|
||||||
dict["params"].clone(),
|
dict.get("params").unwrap().clone(),
|
||||||
f.params
|
f.params
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
@ -74,8 +74,7 @@ fn collect_fn_metadata(ctx: NativeCallContext) -> crate::Array {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Intern strings
|
// Intern strings
|
||||||
let mut dict = HashMap::<&str, ImmutableString>::with_capacity(8);
|
let dict: BTreeSet<ImmutableString> = [
|
||||||
[
|
|
||||||
"namespace",
|
"namespace",
|
||||||
"name",
|
"name",
|
||||||
"access",
|
"access",
|
||||||
@ -85,9 +84,8 @@ fn collect_fn_metadata(ctx: NativeCallContext) -> crate::Array {
|
|||||||
"params",
|
"params",
|
||||||
]
|
]
|
||||||
.iter()
|
.iter()
|
||||||
.for_each(|&s| {
|
.map(|&s| s.into())
|
||||||
dict.insert(s, s.into());
|
.collect();
|
||||||
});
|
|
||||||
|
|
||||||
let mut list: Array = Default::default();
|
let mut list: Array = Default::default();
|
||||||
|
|
||||||
@ -100,7 +98,7 @@ fn collect_fn_metadata(ctx: NativeCallContext) -> crate::Array {
|
|||||||
// Recursively scan modules for script-defined functions.
|
// Recursively scan modules for script-defined functions.
|
||||||
fn scan_module(
|
fn scan_module(
|
||||||
list: &mut Array,
|
list: &mut Array,
|
||||||
dict: &HashMap<&str, ImmutableString>,
|
dict: &BTreeSet<ImmutableString>,
|
||||||
namespace: ImmutableString,
|
namespace: ImmutableString,
|
||||||
module: &Module,
|
module: &Module,
|
||||||
) {
|
) {
|
||||||
|
@ -46,12 +46,12 @@ mod map_functions {
|
|||||||
ctx: NativeCallContext,
|
ctx: NativeCallContext,
|
||||||
map: &mut Map,
|
map: &mut Map,
|
||||||
mut map2: Map,
|
mut map2: Map,
|
||||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
) -> Result<bool, Box<EvalAltResult>> {
|
||||||
if map.len() != map2.len() {
|
if map.len() != map2.len() {
|
||||||
return Ok(false.into());
|
return Ok(false);
|
||||||
}
|
}
|
||||||
if map.is_empty() {
|
if map.is_empty() {
|
||||||
return Ok(true.into());
|
return Ok(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (m1, v1) in map.iter_mut() {
|
for (m1, v1) in map.iter_mut() {
|
||||||
@ -61,22 +61,22 @@ mod map_functions {
|
|||||||
.map(|v| v.as_bool().unwrap_or(false))?;
|
.map(|v| v.as_bool().unwrap_or(false))?;
|
||||||
|
|
||||||
if !equals {
|
if !equals {
|
||||||
return Ok(false.into());
|
return Ok(false);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Ok(false.into());
|
return Ok(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(true.into())
|
Ok(true)
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "!=", return_raw, pure)]
|
#[rhai_fn(name = "!=", return_raw, pure)]
|
||||||
pub fn not_equals(
|
pub fn not_equals(
|
||||||
ctx: NativeCallContext,
|
ctx: NativeCallContext,
|
||||||
map: &mut Map,
|
map: &mut Map,
|
||||||
map2: Map,
|
map2: Map,
|
||||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
) -> Result<bool, Box<EvalAltResult>> {
|
||||||
equals(ctx, map, map2).map(|r| (!r.as_bool().unwrap()).into())
|
equals(ctx, map, map2).map(|r| !r)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
@ -113,7 +113,7 @@ def_package!(crate:BasicMathPackage:"Basic mathematic functions.", lib, {
|
|||||||
#[export_module]
|
#[export_module]
|
||||||
mod int_functions {
|
mod int_functions {
|
||||||
#[rhai_fn(name = "parse_int", return_raw)]
|
#[rhai_fn(name = "parse_int", return_raw)]
|
||||||
pub fn parse_int_radix(s: &str, radix: INT) -> Result<Dynamic, Box<EvalAltResult>> {
|
pub fn parse_int_radix(s: &str, radix: INT) -> Result<INT, Box<EvalAltResult>> {
|
||||||
if radix < 2 || radix > 36 {
|
if radix < 2 || radix > 36 {
|
||||||
return EvalAltResult::ErrorArithmetic(
|
return EvalAltResult::ErrorArithmetic(
|
||||||
format!("Invalid radix: '{}'", radix),
|
format!("Invalid radix: '{}'", radix),
|
||||||
@ -122,9 +122,7 @@ mod int_functions {
|
|||||||
.into();
|
.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
INT::from_str_radix(s.trim(), radix as u32)
|
INT::from_str_radix(s.trim(), radix as u32).map_err(|err| {
|
||||||
.map(Into::<Dynamic>::into)
|
|
||||||
.map_err(|err| {
|
|
||||||
EvalAltResult::ErrorArithmetic(
|
EvalAltResult::ErrorArithmetic(
|
||||||
format!("Error parsing integer number '{}': {}", s, err),
|
format!("Error parsing integer number '{}': {}", s, err),
|
||||||
Position::NONE,
|
Position::NONE,
|
||||||
@ -133,7 +131,7 @@ mod int_functions {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "parse_int", return_raw)]
|
#[rhai_fn(name = "parse_int", return_raw)]
|
||||||
pub fn parse_int(s: &str) -> Result<Dynamic, Box<EvalAltResult>> {
|
pub fn parse_int(s: &str) -> Result<INT, Box<EvalAltResult>> {
|
||||||
parse_int_radix(s, 10)
|
parse_int_radix(s, 10)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -261,7 +259,7 @@ mod float_functions {
|
|||||||
x.is_infinite()
|
x.is_infinite()
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "to_int", return_raw)]
|
#[rhai_fn(name = "to_int", return_raw)]
|
||||||
pub fn f32_to_int(x: f32) -> Result<Dynamic, Box<EvalAltResult>> {
|
pub fn f32_to_int(x: f32) -> Result<INT, Box<EvalAltResult>> {
|
||||||
if cfg!(not(feature = "unchecked")) && x > (MAX_INT as f32) {
|
if cfg!(not(feature = "unchecked")) && x > (MAX_INT as f32) {
|
||||||
EvalAltResult::ErrorArithmetic(
|
EvalAltResult::ErrorArithmetic(
|
||||||
format!("Integer overflow: to_int({})", x),
|
format!("Integer overflow: to_int({})", x),
|
||||||
@ -269,11 +267,11 @@ mod float_functions {
|
|||||||
)
|
)
|
||||||
.into()
|
.into()
|
||||||
} else {
|
} else {
|
||||||
Ok((x.trunc() as INT).into())
|
Ok(x.trunc() as INT)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "to_int", return_raw)]
|
#[rhai_fn(name = "to_int", return_raw)]
|
||||||
pub fn f64_to_int(x: f64) -> Result<Dynamic, Box<EvalAltResult>> {
|
pub fn f64_to_int(x: f64) -> Result<INT, Box<EvalAltResult>> {
|
||||||
if cfg!(not(feature = "unchecked")) && x > (MAX_INT as f64) {
|
if cfg!(not(feature = "unchecked")) && x > (MAX_INT as f64) {
|
||||||
EvalAltResult::ErrorArithmetic(
|
EvalAltResult::ErrorArithmetic(
|
||||||
format!("Integer overflow: to_int({})", x),
|
format!("Integer overflow: to_int({})", x),
|
||||||
@ -281,15 +279,12 @@ mod float_functions {
|
|||||||
)
|
)
|
||||||
.into()
|
.into()
|
||||||
} else {
|
} else {
|
||||||
Ok((x.trunc() as INT).into())
|
Ok(x.trunc() as INT)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[rhai_fn(return_raw)]
|
#[rhai_fn(return_raw)]
|
||||||
pub fn parse_float(s: &str) -> Result<Dynamic, Box<EvalAltResult>> {
|
pub fn parse_float(s: &str) -> Result<FLOAT, Box<EvalAltResult>> {
|
||||||
s.trim()
|
s.trim().parse::<FLOAT>().map_err(|err| {
|
||||||
.parse::<FLOAT>()
|
|
||||||
.map(Into::<Dynamic>::into)
|
|
||||||
.map_err(|err| {
|
|
||||||
EvalAltResult::ErrorArithmetic(
|
EvalAltResult::ErrorArithmetic(
|
||||||
format!("Error parsing floating-point number '{}': {}", s, err),
|
format!("Error parsing floating-point number '{}': {}", s, err),
|
||||||
Position::NONE,
|
Position::NONE,
|
||||||
@ -309,6 +304,7 @@ mod float_functions {
|
|||||||
#[cfg(feature = "decimal")]
|
#[cfg(feature = "decimal")]
|
||||||
#[export_module]
|
#[export_module]
|
||||||
mod decimal_functions {
|
mod decimal_functions {
|
||||||
|
use crate::stdlib::convert::TryFrom;
|
||||||
use rust_decimal::{
|
use rust_decimal::{
|
||||||
prelude::{FromStr, RoundingStrategy},
|
prelude::{FromStr, RoundingStrategy},
|
||||||
Decimal,
|
Decimal,
|
||||||
@ -327,10 +323,10 @@ mod decimal_functions {
|
|||||||
x.round()
|
x.round()
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "round", return_raw)]
|
#[rhai_fn(name = "round", return_raw)]
|
||||||
pub fn round_dp(x: Decimal, dp: INT) -> Result<Dynamic, Box<EvalAltResult>> {
|
pub fn round_dp(x: Decimal, dp: INT) -> Result<Decimal, Box<EvalAltResult>> {
|
||||||
if cfg!(not(feature = "unchecked")) {
|
if cfg!(not(feature = "unchecked")) {
|
||||||
if cfg!(not(feature = "only_i32")) && dp > (u32::MAX as INT) {
|
if cfg!(not(feature = "only_i32")) && dp > (u32::MAX as INT) {
|
||||||
return Ok(x.into());
|
return Ok(x);
|
||||||
}
|
}
|
||||||
if dp < 0 {
|
if dp < 0 {
|
||||||
return Err(make_err(format!(
|
return Err(make_err(format!(
|
||||||
@ -340,13 +336,13 @@ mod decimal_functions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(x.round_dp(dp as u32).into())
|
Ok(x.round_dp(dp as u32))
|
||||||
}
|
}
|
||||||
#[rhai_fn(return_raw)]
|
#[rhai_fn(return_raw)]
|
||||||
pub fn round_up(x: Decimal, dp: INT) -> Result<Dynamic, Box<EvalAltResult>> {
|
pub fn round_up(x: Decimal, dp: INT) -> Result<Decimal, Box<EvalAltResult>> {
|
||||||
if cfg!(not(feature = "unchecked")) {
|
if cfg!(not(feature = "unchecked")) {
|
||||||
if cfg!(not(feature = "only_i32")) && dp > (u32::MAX as INT) {
|
if cfg!(not(feature = "only_i32")) && dp > (u32::MAX as INT) {
|
||||||
return Ok(x.into());
|
return Ok(x);
|
||||||
}
|
}
|
||||||
if dp < 0 {
|
if dp < 0 {
|
||||||
return Err(make_err(format!(
|
return Err(make_err(format!(
|
||||||
@ -356,16 +352,13 @@ mod decimal_functions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(
|
Ok(x.round_dp_with_strategy(dp as u32, RoundingStrategy::RoundUp))
|
||||||
x.round_dp_with_strategy(dp as u32, RoundingStrategy::RoundUp)
|
|
||||||
.into(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
#[rhai_fn(return_raw)]
|
#[rhai_fn(return_raw)]
|
||||||
pub fn round_down(x: Decimal, dp: INT) -> Result<Dynamic, Box<EvalAltResult>> {
|
pub fn round_down(x: Decimal, dp: INT) -> Result<Decimal, Box<EvalAltResult>> {
|
||||||
if cfg!(not(feature = "unchecked")) {
|
if cfg!(not(feature = "unchecked")) {
|
||||||
if cfg!(not(feature = "only_i32")) && dp > (u32::MAX as INT) {
|
if cfg!(not(feature = "only_i32")) && dp > (u32::MAX as INT) {
|
||||||
return Ok(x.into());
|
return Ok(x);
|
||||||
}
|
}
|
||||||
if dp < 0 {
|
if dp < 0 {
|
||||||
return Err(make_err(format!(
|
return Err(make_err(format!(
|
||||||
@ -375,16 +368,13 @@ mod decimal_functions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(
|
Ok(x.round_dp_with_strategy(dp as u32, RoundingStrategy::RoundDown))
|
||||||
x.round_dp_with_strategy(dp as u32, RoundingStrategy::RoundDown)
|
|
||||||
.into(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
#[rhai_fn(return_raw)]
|
#[rhai_fn(return_raw)]
|
||||||
pub fn round_half_up(x: Decimal, dp: INT) -> Result<Dynamic, Box<EvalAltResult>> {
|
pub fn round_half_up(x: Decimal, dp: INT) -> Result<Decimal, Box<EvalAltResult>> {
|
||||||
if cfg!(not(feature = "unchecked")) {
|
if cfg!(not(feature = "unchecked")) {
|
||||||
if cfg!(not(feature = "only_i32")) && dp > (u32::MAX as INT) {
|
if cfg!(not(feature = "only_i32")) && dp > (u32::MAX as INT) {
|
||||||
return Ok(x.into());
|
return Ok(x);
|
||||||
}
|
}
|
||||||
if dp < 0 {
|
if dp < 0 {
|
||||||
return Err(make_err(format!(
|
return Err(make_err(format!(
|
||||||
@ -394,16 +384,13 @@ mod decimal_functions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(
|
Ok(x.round_dp_with_strategy(dp as u32, RoundingStrategy::RoundHalfUp))
|
||||||
x.round_dp_with_strategy(dp as u32, RoundingStrategy::RoundHalfUp)
|
|
||||||
.into(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
#[rhai_fn(return_raw)]
|
#[rhai_fn(return_raw)]
|
||||||
pub fn round_half_down(x: Decimal, dp: INT) -> Result<Dynamic, Box<EvalAltResult>> {
|
pub fn round_half_down(x: Decimal, dp: INT) -> Result<Decimal, Box<EvalAltResult>> {
|
||||||
if cfg!(not(feature = "unchecked")) {
|
if cfg!(not(feature = "unchecked")) {
|
||||||
if cfg!(not(feature = "only_i32")) && dp > (u32::MAX as INT) {
|
if cfg!(not(feature = "only_i32")) && dp > (u32::MAX as INT) {
|
||||||
return Ok(x.into());
|
return Ok(x);
|
||||||
}
|
}
|
||||||
if dp < 0 {
|
if dp < 0 {
|
||||||
return Err(make_err(format!(
|
return Err(make_err(format!(
|
||||||
@ -413,10 +400,7 @@ mod decimal_functions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(
|
Ok(x.round_dp_with_strategy(dp as u32, RoundingStrategy::RoundHalfDown))
|
||||||
x.round_dp_with_strategy(dp as u32, RoundingStrategy::RoundHalfDown)
|
|
||||||
.into(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "int", get = "int")]
|
#[rhai_fn(name = "int", get = "int")]
|
||||||
pub fn int(x: Decimal) -> Decimal {
|
pub fn int(x: Decimal) -> Decimal {
|
||||||
@ -427,10 +411,9 @@ mod decimal_functions {
|
|||||||
x.fract()
|
x.fract()
|
||||||
}
|
}
|
||||||
#[rhai_fn(return_raw)]
|
#[rhai_fn(return_raw)]
|
||||||
pub fn parse_decimal(s: &str) -> Result<Dynamic, Box<EvalAltResult>> {
|
pub fn parse_decimal(s: &str) -> Result<Decimal, Box<EvalAltResult>> {
|
||||||
Decimal::from_str(s)
|
Decimal::from_str(s)
|
||||||
.or_else(|_| Decimal::from_scientific(s))
|
.or_else(|_| Decimal::from_scientific(s))
|
||||||
.map(Into::<Dynamic>::into)
|
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
EvalAltResult::ErrorArithmetic(
|
EvalAltResult::ErrorArithmetic(
|
||||||
format!("Error parsing decimal number '{}': {}", s, err),
|
format!("Error parsing decimal number '{}': {}", s, err),
|
||||||
@ -439,6 +422,40 @@ mod decimal_functions {
|
|||||||
.into()
|
.into()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
pub mod float {
|
||||||
|
#[rhai_fn(name = "to_decimal", return_raw)]
|
||||||
|
pub fn f32_to_decimal(x: f32) -> Result<Decimal, Box<EvalAltResult>> {
|
||||||
|
Decimal::try_from(x).map_err(|_| {
|
||||||
|
EvalAltResult::ErrorArithmetic(
|
||||||
|
format!("Cannot convert to Decimal: to_decimal({})", x),
|
||||||
|
Position::NONE,
|
||||||
|
)
|
||||||
|
.into()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
#[rhai_fn(name = "to_decimal", return_raw)]
|
||||||
|
pub fn f64_to_decimal(x: f64) -> Result<Decimal, Box<EvalAltResult>> {
|
||||||
|
Decimal::try_from(x).map_err(|_| {
|
||||||
|
EvalAltResult::ErrorArithmetic(
|
||||||
|
format!("Cannot convert to Decimal: to_decimal({})", x),
|
||||||
|
Position::NONE,
|
||||||
|
)
|
||||||
|
.into()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
#[rhai_fn(return_raw)]
|
||||||
|
pub fn to_float(x: Decimal) -> Result<FLOAT, Box<EvalAltResult>> {
|
||||||
|
FLOAT::try_from(x).map_err(|_| {
|
||||||
|
EvalAltResult::ErrorArithmetic(
|
||||||
|
format!("Cannot convert to floating-point: to_float({})", x),
|
||||||
|
Position::NONE,
|
||||||
|
)
|
||||||
|
.into()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
@ -89,7 +89,7 @@ macro_rules! def_package {
|
|||||||
|
|
||||||
impl $package {
|
impl $package {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let mut module = $root::Module::new_with_capacity(1024);
|
let mut module = $root::Module::new();
|
||||||
<Self as $root::packages::Package>::init(&mut module);
|
<Self as $root::packages::Package>::init(&mut module);
|
||||||
module.build_index();
|
module.build_index();
|
||||||
Self(module.into())
|
Self(module.into())
|
||||||
|
@ -235,7 +235,7 @@ mod string_functions {
|
|||||||
string: &mut ImmutableString,
|
string: &mut ImmutableString,
|
||||||
len: INT,
|
len: INT,
|
||||||
character: char,
|
character: char,
|
||||||
) -> Result<Dynamic, Box<crate::EvalAltResult>> {
|
) -> Result<(), Box<crate::EvalAltResult>> {
|
||||||
// Check if string will be over max size limit
|
// Check if string will be over max size limit
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
if _ctx.engine().max_string_size() > 0 && len as usize > _ctx.engine().max_string_size() {
|
if _ctx.engine().max_string_size() > 0 && len as usize > _ctx.engine().max_string_size() {
|
||||||
@ -269,7 +269,7 @@ mod string_functions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Dynamic::UNIT)
|
Ok(())
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "pad", return_raw)]
|
#[rhai_fn(name = "pad", return_raw)]
|
||||||
pub fn pad_with_string(
|
pub fn pad_with_string(
|
||||||
@ -277,7 +277,7 @@ mod string_functions {
|
|||||||
string: &mut ImmutableString,
|
string: &mut ImmutableString,
|
||||||
len: INT,
|
len: INT,
|
||||||
padding: &str,
|
padding: &str,
|
||||||
) -> Result<Dynamic, Box<crate::EvalAltResult>> {
|
) -> Result<(), Box<crate::EvalAltResult>> {
|
||||||
// Check if string will be over max size limit
|
// Check if string will be over max size limit
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
if _ctx.engine().max_string_size() > 0 && len as usize > _ctx.engine().max_string_size() {
|
if _ctx.engine().max_string_size() > 0 && len as usize > _ctx.engine().max_string_size() {
|
||||||
@ -318,7 +318,7 @@ mod string_functions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Dynamic::UNIT)
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
@ -143,28 +143,28 @@ mod time_functions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[rhai_fn(return_raw, name = "+")]
|
#[rhai_fn(return_raw, name = "+")]
|
||||||
pub fn add(timestamp: Instant, seconds: FLOAT) -> Result<Dynamic, Box<EvalAltResult>> {
|
pub fn add(timestamp: Instant, seconds: FLOAT) -> Result<Instant, Box<EvalAltResult>> {
|
||||||
add_impl(timestamp, seconds).map(Into::<Dynamic>::into)
|
add_impl(timestamp, seconds)
|
||||||
}
|
}
|
||||||
#[rhai_fn(return_raw, name = "+=")]
|
#[rhai_fn(return_raw, name = "+=")]
|
||||||
pub fn add_assign(
|
pub fn add_assign(
|
||||||
timestamp: &mut Instant,
|
timestamp: &mut Instant,
|
||||||
seconds: FLOAT,
|
seconds: FLOAT,
|
||||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
) -> Result<(), Box<EvalAltResult>> {
|
||||||
*timestamp = add_impl(*timestamp, seconds)?;
|
*timestamp = add_impl(*timestamp, seconds)?;
|
||||||
Ok(Dynamic::UNIT)
|
Ok(())
|
||||||
}
|
}
|
||||||
#[rhai_fn(return_raw, name = "-")]
|
#[rhai_fn(return_raw, name = "-")]
|
||||||
pub fn subtract(timestamp: Instant, seconds: FLOAT) -> Result<Dynamic, Box<EvalAltResult>> {
|
pub fn subtract(timestamp: Instant, seconds: FLOAT) -> Result<Instant, Box<EvalAltResult>> {
|
||||||
subtract_impl(timestamp, seconds).map(Into::<Dynamic>::into)
|
subtract_impl(timestamp, seconds)
|
||||||
}
|
}
|
||||||
#[rhai_fn(return_raw, name = "-=")]
|
#[rhai_fn(return_raw, name = "-=")]
|
||||||
pub fn subtract_assign(
|
pub fn subtract_assign(
|
||||||
timestamp: &mut Instant,
|
timestamp: &mut Instant,
|
||||||
seconds: FLOAT,
|
seconds: FLOAT,
|
||||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
) -> Result<(), Box<EvalAltResult>> {
|
||||||
*timestamp = subtract_impl(*timestamp, seconds)?;
|
*timestamp = subtract_impl(*timestamp, seconds)?;
|
||||||
Ok(Dynamic::UNIT)
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,28 +202,25 @@ mod time_functions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[rhai_fn(return_raw, name = "+")]
|
#[rhai_fn(return_raw, name = "+")]
|
||||||
pub fn add(timestamp: Instant, seconds: INT) -> Result<Dynamic, Box<EvalAltResult>> {
|
pub fn add(timestamp: Instant, seconds: INT) -> Result<Instant, Box<EvalAltResult>> {
|
||||||
add_impl(timestamp, seconds).map(Into::<Dynamic>::into)
|
add_impl(timestamp, seconds)
|
||||||
}
|
}
|
||||||
#[rhai_fn(return_raw, name = "+=")]
|
#[rhai_fn(return_raw, name = "+=")]
|
||||||
pub fn add_assign(
|
pub fn add_assign(timestamp: &mut Instant, seconds: INT) -> Result<(), Box<EvalAltResult>> {
|
||||||
timestamp: &mut Instant,
|
|
||||||
seconds: INT,
|
|
||||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
|
||||||
*timestamp = add_impl(*timestamp, seconds)?;
|
*timestamp = add_impl(*timestamp, seconds)?;
|
||||||
Ok(Dynamic::UNIT)
|
Ok(())
|
||||||
}
|
}
|
||||||
#[rhai_fn(return_raw, name = "-")]
|
#[rhai_fn(return_raw, name = "-")]
|
||||||
pub fn subtract(timestamp: Instant, seconds: INT) -> Result<Dynamic, Box<EvalAltResult>> {
|
pub fn subtract(timestamp: Instant, seconds: INT) -> Result<Instant, Box<EvalAltResult>> {
|
||||||
subtract_impl(timestamp, seconds).map(Into::<Dynamic>::into)
|
subtract_impl(timestamp, seconds)
|
||||||
}
|
}
|
||||||
#[rhai_fn(return_raw, name = "-=")]
|
#[rhai_fn(return_raw, name = "-=")]
|
||||||
pub fn subtract_assign(
|
pub fn subtract_assign(
|
||||||
timestamp: &mut Instant,
|
timestamp: &mut Instant,
|
||||||
seconds: INT,
|
seconds: INT,
|
||||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
) -> Result<(), Box<EvalAltResult>> {
|
||||||
*timestamp = subtract_impl(*timestamp, seconds)?;
|
*timestamp = subtract_impl(*timestamp, seconds)?;
|
||||||
Ok(Dynamic::UNIT)
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rhai_fn(name = "==")]
|
#[rhai_fn(name = "==")]
|
||||||
|
@ -12,7 +12,7 @@ use crate::optimize::OptimizationLevel;
|
|||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
boxed::Box,
|
boxed::Box,
|
||||||
collections::HashMap,
|
collections::BTreeMap,
|
||||||
format,
|
format,
|
||||||
hash::{Hash, Hasher},
|
hash::{Hash, Hasher},
|
||||||
iter::empty,
|
iter::empty,
|
||||||
@ -23,7 +23,7 @@ use crate::stdlib::{
|
|||||||
};
|
};
|
||||||
use crate::syntax::{CustomSyntax, MARKER_BLOCK, MARKER_EXPR, MARKER_IDENT};
|
use crate::syntax::{CustomSyntax, MARKER_BLOCK, MARKER_EXPR, MARKER_IDENT};
|
||||||
use crate::token::{is_keyword_function, is_valid_identifier, Token, TokenStream};
|
use crate::token::{is_keyword_function, is_valid_identifier, Token, TokenStream};
|
||||||
use crate::utils::{get_hasher, StraightHasherBuilder};
|
use crate::utils::get_hasher;
|
||||||
use crate::{
|
use crate::{
|
||||||
calc_fn_hash, Dynamic, Engine, ImmutableString, LexError, ParseError, ParseErrorType, Position,
|
calc_fn_hash, Dynamic, Engine, ImmutableString, LexError, ParseError, ParseErrorType, Position,
|
||||||
Scope, Shared, StaticVec, AST,
|
Scope, Shared, StaticVec, AST,
|
||||||
@ -37,7 +37,7 @@ use crate::FnAccess;
|
|||||||
|
|
||||||
type PERR = ParseErrorType;
|
type PERR = ParseErrorType;
|
||||||
|
|
||||||
type FunctionsLib = HashMap<u64, Shared<ScriptFnDef>, StraightHasherBuilder>;
|
type FunctionsLib = BTreeMap<u64, Shared<ScriptFnDef>>;
|
||||||
|
|
||||||
/// A type that encapsulates the current state of the parser.
|
/// A type that encapsulates the current state of the parser.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -45,14 +45,14 @@ struct ParseState<'e> {
|
|||||||
/// Reference to the scripting [`Engine`].
|
/// Reference to the scripting [`Engine`].
|
||||||
engine: &'e Engine,
|
engine: &'e Engine,
|
||||||
/// Interned strings.
|
/// Interned strings.
|
||||||
strings: HashMap<String, ImmutableString>,
|
interned_strings: BTreeMap<String, ImmutableString>,
|
||||||
/// Encapsulates a local stack with variable names to simulate an actual runtime scope.
|
/// Encapsulates a local stack with variable names to simulate an actual runtime scope.
|
||||||
stack: Vec<(ImmutableString, AccessMode)>,
|
stack: Vec<(ImmutableString, AccessMode)>,
|
||||||
/// Size of the local variables stack upon entry of the current block scope.
|
/// Size of the local variables stack upon entry of the current block scope.
|
||||||
entry_stack_len: usize,
|
entry_stack_len: usize,
|
||||||
/// Tracks a list of external variables (variables that are not explicitly declared in the scope).
|
/// Tracks a list of external variables (variables that are not explicitly declared in the scope).
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
externals: HashMap<ImmutableString, Position>,
|
external_vars: BTreeMap<ImmutableString, Position>,
|
||||||
/// An indicator that disables variable capturing into externals one single time
|
/// An indicator that disables variable capturing into externals one single time
|
||||||
/// up until the nearest consumed Identifier token.
|
/// up until the nearest consumed Identifier token.
|
||||||
/// If set to false the next call to `access_var` will not capture the variable.
|
/// If set to false the next call to `access_var` will not capture the variable.
|
||||||
@ -89,10 +89,10 @@ impl<'e> ParseState<'e> {
|
|||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
max_function_expr_depth,
|
max_function_expr_depth,
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
externals: Default::default(),
|
external_vars: Default::default(),
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
allow_capture: true,
|
allow_capture: true,
|
||||||
strings: HashMap::with_capacity(64),
|
interned_strings: Default::default(),
|
||||||
stack: Vec::with_capacity(16),
|
stack: Vec::with_capacity(16),
|
||||||
entry_stack_len: 0,
|
entry_stack_len: 0,
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
@ -130,8 +130,8 @@ impl<'e> ParseState<'e> {
|
|||||||
|
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
if self.allow_capture {
|
if self.allow_capture {
|
||||||
if index.is_none() && !self.externals.contains_key(name) {
|
if index.is_none() && !self.external_vars.contains_key(name) {
|
||||||
self.externals.insert(name.into(), _pos);
|
self.external_vars.insert(name.into(), _pos);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.allow_capture = true
|
self.allow_capture = true
|
||||||
@ -171,12 +171,13 @@ impl<'e> ParseState<'e> {
|
|||||||
text: impl AsRef<str> + Into<ImmutableString>,
|
text: impl AsRef<str> + Into<ImmutableString>,
|
||||||
) -> ImmutableString {
|
) -> ImmutableString {
|
||||||
#[allow(clippy::map_entry)]
|
#[allow(clippy::map_entry)]
|
||||||
if !self.strings.contains_key(text.as_ref()) {
|
if !self.interned_strings.contains_key(text.as_ref()) {
|
||||||
let value = text.into();
|
let value = text.into();
|
||||||
self.strings.insert(value.clone().into(), value.clone());
|
self.interned_strings
|
||||||
|
.insert(value.clone().into(), value.clone());
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
self.strings.get(text.as_ref()).unwrap().clone()
|
self.interned_strings.get(text.as_ref()).unwrap().clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -813,7 +814,7 @@ fn parse_switch(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut table = HashMap::<u64, StmtBlock>::new();
|
let mut table = BTreeMap::<u64, StmtBlock>::new();
|
||||||
let mut def_stmt = None;
|
let mut def_stmt = None;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
@ -902,13 +903,10 @@ fn parse_switch(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut final_table = HashMap::with_capacity_and_hasher(table.len(), StraightHasherBuilder);
|
|
||||||
final_table.extend(table.into_iter());
|
|
||||||
|
|
||||||
Ok(Stmt::Switch(
|
Ok(Stmt::Switch(
|
||||||
item,
|
item,
|
||||||
Box::new((
|
Box::new((
|
||||||
final_table.into(),
|
table,
|
||||||
def_stmt.unwrap_or_else(|| Stmt::Noop(Position::NONE).into()),
|
def_stmt.unwrap_or_else(|| Stmt::Noop(Position::NONE).into()),
|
||||||
)),
|
)),
|
||||||
settings.pos,
|
settings.pos,
|
||||||
@ -1003,7 +1001,7 @@ fn parse_primary(
|
|||||||
let (expr, func) = parse_anon_fn(input, &mut new_state, lib, settings)?;
|
let (expr, func) = parse_anon_fn(input, &mut new_state, lib, settings)?;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
new_state.externals.iter().for_each(|(closure, pos)| {
|
new_state.external_vars.iter().for_each(|(closure, pos)| {
|
||||||
state.access_var(closure, *pos);
|
state.access_var(closure, *pos);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -2739,7 +2737,7 @@ fn parse_fn(
|
|||||||
|
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
let externals = state
|
let externals = state
|
||||||
.externals
|
.external_vars
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(name, _)| name)
|
.map(|(name, _)| name)
|
||||||
.filter(|name| !params.contains(name))
|
.filter(|name| !params.contains(name))
|
||||||
@ -2860,7 +2858,7 @@ fn parse_anon_fn(
|
|||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
{
|
{
|
||||||
state
|
state
|
||||||
.externals
|
.external_vars
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(name, &pos)| Ident {
|
.map(|(name, &pos)| Ident {
|
||||||
name: name.clone(),
|
name: name.clone(),
|
||||||
@ -2966,7 +2964,7 @@ impl Engine {
|
|||||||
input: &mut TokenStream,
|
input: &mut TokenStream,
|
||||||
) -> Result<(Vec<Stmt>, Vec<Shared<ScriptFnDef>>), ParseError> {
|
) -> Result<(Vec<Stmt>, Vec<Shared<ScriptFnDef>>), ParseError> {
|
||||||
let mut statements = Vec::with_capacity(16);
|
let mut statements = Vec::with_capacity(16);
|
||||||
let mut functions = HashMap::with_capacity_and_hasher(16, StraightHasherBuilder);
|
let mut functions = BTreeMap::new();
|
||||||
let mut state = ParseState::new(
|
let mut state = ParseState::new(
|
||||||
self,
|
self,
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
@ -2,11 +2,11 @@
|
|||||||
|
|
||||||
pub use crate::fn_native::{CallableFunction, FnCallArgs};
|
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::stdlib::{any::TypeId, boxed::Box, format, mem, string::ToString, vec as new_vec};
|
||||||
use crate::RhaiResult;
|
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
Dynamic, Engine, EvalAltResult, FnAccess, FnNamespace, ImmutableString, Module,
|
Dynamic, Engine, EvalAltResult, FnAccess, FnNamespace, ImmutableString, Module,
|
||||||
NativeCallContext, Position,
|
NativeCallContext, Position,
|
||||||
};
|
};
|
||||||
|
pub type RhaiResult = Result<Dynamic, Box<EvalAltResult>>;
|
||||||
|
|
||||||
#[cfg(not(features = "no_module"))]
|
#[cfg(not(features = "no_module"))]
|
||||||
pub use rhai_codegen::*;
|
pub use rhai_codegen::*;
|
||||||
@ -30,12 +30,9 @@ pub trait PluginFunction {
|
|||||||
/// Convert a plugin function into a boxed trait object.
|
/// Convert a plugin function into a boxed trait object.
|
||||||
fn clone_boxed(&self) -> Box<dyn PluginFunction>;
|
fn clone_boxed(&self) -> Box<dyn PluginFunction>;
|
||||||
|
|
||||||
/// Return a boxed slice of the names of the function's parameters.
|
/// Return a boxed slice of the names of the function's parameters and return type.
|
||||||
fn input_names(&self) -> Box<[&'static str]>;
|
fn param_names(&self) -> Box<[&'static str]>;
|
||||||
|
|
||||||
/// Return a boxed slice of type ID's of the function's parameters.
|
/// Return a boxed slice of type ID's of the function's parameters.
|
||||||
fn input_types(&self) -> Box<[TypeId]>;
|
fn input_types(&self) -> Box<[TypeId]>;
|
||||||
|
|
||||||
/// Return a string slice of the function's return type.
|
|
||||||
fn return_type(&self) -> &'static str;
|
|
||||||
}
|
}
|
||||||
|
@ -390,7 +390,7 @@ impl Serializer for &mut DynamicSerializer {
|
|||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
return Ok(StructVariantSerializer {
|
return Ok(StructVariantSerializer {
|
||||||
variant: _variant,
|
variant: _variant,
|
||||||
map: Map::with_capacity(_len),
|
map: Default::default(),
|
||||||
});
|
});
|
||||||
#[cfg(feature = "no_object")]
|
#[cfg(feature = "no_object")]
|
||||||
return EvalAltResult::ErrorMismatchDataType(
|
return EvalAltResult::ErrorMismatchDataType(
|
||||||
@ -691,7 +691,7 @@ impl serde::ser::SerializeStructVariant for StructVariantSerializer {
|
|||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
fn make_variant(variant: &'static str, value: Dynamic) -> RhaiResult {
|
fn make_variant(variant: &'static str, value: Dynamic) -> RhaiResult {
|
||||||
let mut map = Map::with_capacity(1);
|
let mut map = Map::new();
|
||||||
map.insert(variant.into(), value);
|
map.insert(variant.into(), value);
|
||||||
Ok(map.into())
|
Ok(map.into())
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,8 @@ mod inner {
|
|||||||
pub use core_error as error;
|
pub use core_error as error;
|
||||||
|
|
||||||
pub mod collections {
|
pub mod collections {
|
||||||
pub use hashbrown::{hash_map, hash_set, HashMap, HashSet};
|
pub use alloc::collections::btree_map::BTreeMap;
|
||||||
|
pub use alloc::collections::btree_set::BTreeSet;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ use crate::stdlib::{
|
|||||||
|
|
||||||
/// Cast a type into another type.
|
/// Cast a type into another type.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn unsafe_try_cast<A: Any, B: Any>(a: A) -> Option<B> {
|
pub fn unsafe_try_cast<A: Any, B: Any>(a: A) -> Result<B, A> {
|
||||||
if TypeId::of::<B>() == a.type_id() {
|
if TypeId::of::<B>() == a.type_id() {
|
||||||
// SAFETY: Just checked we have the right type. We explicitly forget the
|
// SAFETY: Just checked we have the right type. We explicitly forget the
|
||||||
// value immediately after moving out, removing any chance of a destructor
|
// value immediately after moving out, removing any chance of a destructor
|
||||||
@ -17,10 +17,10 @@ pub fn unsafe_try_cast<A: Any, B: Any>(a: A) -> Option<B> {
|
|||||||
unsafe {
|
unsafe {
|
||||||
let ret: B = ptr::read(&a as *const _ as *const B);
|
let ret: B = ptr::read(&a as *const _ as *const B);
|
||||||
mem::forget(a);
|
mem::forget(a);
|
||||||
Some(ret)
|
Ok(ret)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
Err(a)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
60
src/utils.rs
60
src/utils.rs
@ -6,15 +6,13 @@ use crate::stdlib::{
|
|||||||
borrow::Borrow,
|
borrow::Borrow,
|
||||||
boxed::Box,
|
boxed::Box,
|
||||||
cmp::Ordering,
|
cmp::Ordering,
|
||||||
collections::HashMap,
|
|
||||||
fmt,
|
fmt,
|
||||||
fmt::{Debug, Display},
|
fmt::{Debug, Display},
|
||||||
hash::{BuildHasher, Hash, Hasher},
|
hash::{BuildHasher, Hash, Hasher},
|
||||||
iter::FromIterator,
|
iter::FromIterator,
|
||||||
ops::{Add, AddAssign, Deref, DerefMut, Sub, SubAssign},
|
ops::{Add, AddAssign, Deref, Sub, SubAssign},
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
string::{String, ToString},
|
string::{String, ToString},
|
||||||
vec::Vec,
|
|
||||||
};
|
};
|
||||||
use crate::Shared;
|
use crate::Shared;
|
||||||
|
|
||||||
@ -106,62 +104,6 @@ pub(crate) fn combine_hashes(a: u64, b: u64) -> u64 {
|
|||||||
a ^ b
|
a ^ b
|
||||||
}
|
}
|
||||||
|
|
||||||
/// _(INTERNALS)_ A type that wraps a [`HashMap`] and implements [`Hash`].
|
|
||||||
/// Exported under the `internals` feature only.
|
|
||||||
#[derive(Clone, Default)]
|
|
||||||
pub struct HashableHashMap<K, T, H: BuildHasher>(HashMap<K, T, H>);
|
|
||||||
|
|
||||||
impl<K, T, H: BuildHasher> From<HashMap<K, T, H>> for HashableHashMap<K, T, H> {
|
|
||||||
#[inline(always)]
|
|
||||||
fn from(value: HashMap<K, T, H>) -> Self {
|
|
||||||
Self(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<K, T, H: BuildHasher> AsRef<HashMap<K, T, H>> for HashableHashMap<K, T, H> {
|
|
||||||
#[inline(always)]
|
|
||||||
fn as_ref(&self) -> &HashMap<K, T, H> {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<K, T, H: BuildHasher> AsMut<HashMap<K, T, H>> for HashableHashMap<K, T, H> {
|
|
||||||
#[inline(always)]
|
|
||||||
fn as_mut(&mut self) -> &mut HashMap<K, T, H> {
|
|
||||||
&mut self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<K, T, H: BuildHasher> Deref for HashableHashMap<K, T, H> {
|
|
||||||
type Target = HashMap<K, T, H>;
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<K, T, H: BuildHasher> DerefMut for HashableHashMap<K, T, H> {
|
|
||||||
#[inline(always)]
|
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
||||||
&mut self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<K: Debug, T: Debug, H: BuildHasher> Debug for HashableHashMap<K, T, H> {
|
|
||||||
#[inline(always)]
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
self.0.fmt(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<K: Hash + Ord, T: Hash, H: BuildHasher> Hash for HashableHashMap<K, T, H> {
|
|
||||||
#[inline(always)]
|
|
||||||
fn hash<B: Hasher>(&self, state: &mut B) {
|
|
||||||
let mut keys: Vec<_> = self.0.keys().collect();
|
|
||||||
keys.sort();
|
|
||||||
|
|
||||||
keys.into_iter().for_each(|key| {
|
|
||||||
key.hash(state);
|
|
||||||
self.0.get(&key).unwrap().hash(state);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The system immutable string type.
|
/// The system immutable string type.
|
||||||
///
|
///
|
||||||
/// An [`ImmutableString`] wraps an [`Rc`][std::rc::Rc]`<`[`String`]`>`
|
/// An [`ImmutableString`] wraps an [`Rc`][std::rc::Rc]`<`[`String`]`>`
|
||||||
|
Loading…
Reference in New Issue
Block a user