Merge pull request #660 from schungx/master
Code cleanup and minor refactors.
This commit is contained in:
commit
a489b8cdd3
5
.github/workflows/build.yml
vendored
5
.github/workflows/build.yml
vendored
@ -60,10 +60,11 @@ jobs:
|
|||||||
- "--features no_object,serde,metadata,internals,debugging"
|
- "--features no_object,serde,metadata,internals,debugging"
|
||||||
- "--features no_function,serde,metadata,internals,debugging"
|
- "--features no_function,serde,metadata,internals,debugging"
|
||||||
- "--features no_module,serde,metadata,internals,debugging"
|
- "--features no_module,serde,metadata,internals,debugging"
|
||||||
|
- "--features no_time,serde,metadata,internals,debugging"
|
||||||
- "--features no_closure,serde,metadata,internals,debugging"
|
- "--features no_closure,serde,metadata,internals,debugging"
|
||||||
- "--features unicode-xid-ident,serde,metadata,internals,debugging"
|
- "--features unicode-xid-ident,serde,metadata,internals,debugging"
|
||||||
- "--features sync,no_function,no_float,no_position,no_optimize,no_module,no_closure,no_custom_syntax,metadata,serde,unchecked,debugging"
|
- "--features sync,no_time,no_function,no_float,no_position,no_optimize,no_module,no_closure,no_custom_syntax,metadata,serde,unchecked,debugging"
|
||||||
- "--features no_function,no_float,no_position,no_index,no_object,no_optimize,no_module,no_closure,no_custom_syntax,unchecked"
|
- "--features no_time,no_function,no_float,no_position,no_index,no_object,no_optimize,no_module,no_closure,no_custom_syntax,unchecked"
|
||||||
toolchain: [stable]
|
toolchain: [stable]
|
||||||
experimental: [false]
|
experimental: [false]
|
||||||
include:
|
include:
|
||||||
|
@ -54,6 +54,7 @@ Enhancements
|
|||||||
------------
|
------------
|
||||||
|
|
||||||
* `parse_json` function is added to parse a JSON string into an object map.
|
* `parse_json` function is added to parse a JSON string into an object map.
|
||||||
|
* `Error::ErrorNonPureMethodCallOnConstant` is added which is raised when a non-pure method is called on a constant value.
|
||||||
|
|
||||||
|
|
||||||
Version 1.10.1
|
Version 1.10.1
|
||||||
|
11
Cargo.toml
11
Cargo.toml
@ -3,7 +3,7 @@ members = [".", "codegen"]
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "rhai"
|
name = "rhai"
|
||||||
version = "1.10.1"
|
version = "1.11.0"
|
||||||
rust-version = "1.61.0"
|
rust-version = "1.61.0"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
@ -33,6 +33,7 @@ serde = { version = "1.0", default-features = false, features = ["derive", "allo
|
|||||||
serde_json = { version = "1.0", default-features = false, features = ["alloc"], optional = true }
|
serde_json = { version = "1.0", default-features = false, features = ["alloc"], optional = true }
|
||||||
unicode-xid = { version = "0.2", default-features = false, optional = true }
|
unicode-xid = { version = "0.2", default-features = false, optional = true }
|
||||||
rust_decimal = { version = "1.16", default-features = false, features = ["maths"], optional = true }
|
rust_decimal = { version = "1.16", default-features = false, features = ["maths"], optional = true }
|
||||||
|
getrandom = { version = "0.2", optional = true }
|
||||||
rustyline = { version = "10", optional = true }
|
rustyline = { version = "10", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
@ -53,11 +54,11 @@ only_i64 = [] # set INT=i64 (default) and disable support for
|
|||||||
decimal = ["rust_decimal"] # add the Decimal number type
|
decimal = ["rust_decimal"] # add the Decimal number type
|
||||||
no_index = [] # no arrays and indexing
|
no_index = [] # no arrays and indexing
|
||||||
no_object = [] # no custom objects
|
no_object = [] # no custom objects
|
||||||
|
no_time = [] # no timestamps
|
||||||
no_function = ["no_closure"] # no script-defined functions (meaning no closures)
|
no_function = ["no_closure"] # no script-defined functions (meaning no closures)
|
||||||
no_closure = [] # no automatic sharing and capture of anonymous functions to external variables
|
no_closure = [] # no automatic sharing and capture of anonymous functions to external variables
|
||||||
no_module = [] # no modules
|
no_module = [] # no modules
|
||||||
no_custom_syntax = [] # no custom syntax or custom operators
|
no_custom_syntax = [] # no custom syntax or custom operators
|
||||||
no_time = [] # no timestamps
|
|
||||||
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", "rhai_codegen/metadata", "smartstring/serde"] # enable exporting functions metadata
|
metadata = ["serde", "serde_json", "rhai_codegen/metadata", "smartstring/serde"] # enable exporting functions metadata
|
||||||
internals = [] # expose internal data structures
|
internals = [] # expose internal data structures
|
||||||
@ -65,11 +66,11 @@ debugging = ["internals"] # enable debugging
|
|||||||
serde = ["dep:serde", "smartstring/serde", "smallvec/serde"] # implement serde for rhai types
|
serde = ["dep:serde", "smartstring/serde", "smallvec/serde"] # implement serde for rhai types
|
||||||
|
|
||||||
# compiling for no-std
|
# compiling for no-std
|
||||||
no_std = ["no-std-compat", "num-traits/libm", "core-error", "libm", "hashbrown"]
|
no_std = ["no-std-compat", "num-traits/libm", "core-error", "libm", "hashbrown", "no_time"]
|
||||||
|
|
||||||
# compiling for WASM
|
# compiling for WASM
|
||||||
wasm-bindgen = ["instant/wasm-bindgen"]
|
wasm-bindgen = ["getrandom/js", "instant/wasm-bindgen"]
|
||||||
stdweb = ["instant/stdweb"]
|
stdweb = ["getrandom/js", "instant/stdweb"]
|
||||||
|
|
||||||
# compiling bin tools
|
# compiling bin tools
|
||||||
bin-features = ["decimal", "metadata", "serde", "debugging", "rustyline"]
|
bin-features = ["decimal", "metadata", "serde", "debugging", "rustyline"]
|
||||||
|
1
build.rs
1
build.rs
@ -6,6 +6,7 @@ use std::{
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// Tell Cargo that if the given environment variable changes, to rerun this build script.
|
// Tell Cargo that if the given environment variable changes, to rerun this build script.
|
||||||
|
println!("cargo:rerun-if-changed=build.template");
|
||||||
println!("cargo:rerun-if-env-changed=RHAI_AHASH_SEED");
|
println!("cargo:rerun-if-env-changed=RHAI_AHASH_SEED");
|
||||||
|
|
||||||
let mut contents = String::new();
|
let mut contents = String::new();
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
//! Configuration settings for this Rhai build
|
//! Configuration settings for this Rhai build
|
||||||
|
//!
|
||||||
|
//! This file is auto-generated from `build.template`
|
||||||
|
|
||||||
/// Fixed hashing seeds for stable hashing.
|
/// Fixed hashing seeds for stable hashing.
|
||||||
/// Set to [`None`] to disable stable hashing.
|
/// Set to [`None`] to disable stable hashing.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "rhai_codegen"
|
name = "rhai_codegen"
|
||||||
version = "1.4.2"
|
version = "1.4.3"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
authors = ["jhwgh1968", "Stephen Chung"]
|
authors = ["jhwgh1968", "Stephen Chung"]
|
||||||
@ -22,5 +22,5 @@ syn = { version = "1.0", features = ["full", "parsing", "printing", "proc-macro"
|
|||||||
quote = "1"
|
quote = "1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
rhai = { path = "..", version = "1.6", features = ["metadata"] }
|
rhai = { path = "..", version = "1.11", features = ["metadata"] }
|
||||||
trybuild = "1"
|
trybuild = "1"
|
||||||
|
@ -673,6 +673,7 @@ impl ExportedFn {
|
|||||||
let sig_name = self.name().clone();
|
let sig_name = self.name().clone();
|
||||||
let arg_count = self.arg_count();
|
let arg_count = self.arg_count();
|
||||||
let is_method_call = self.mutable_receiver();
|
let is_method_call = self.mutable_receiver();
|
||||||
|
let is_pure = !self.mutable_receiver() || self.params().pure.is_some();
|
||||||
|
|
||||||
let mut unpack_statements = Vec::new();
|
let mut unpack_statements = Vec::new();
|
||||||
let mut unpack_exprs = Vec::new();
|
let mut unpack_exprs = Vec::new();
|
||||||
@ -713,18 +714,6 @@ impl ExportedFn {
|
|||||||
})
|
})
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
);
|
);
|
||||||
if self.params().pure.is_none() {
|
|
||||||
let arg_lit_str =
|
|
||||||
syn::LitStr::new(&pat.to_token_stream().to_string(), pat.span());
|
|
||||||
unpack_statements.push(
|
|
||||||
syn::parse2::<syn::Stmt>(quote! {
|
|
||||||
if args[0usize].is_read_only() {
|
|
||||||
return Err(EvalAltResult::ErrorAssignmentToConstant(#arg_lit_str.to_string(), Position::NONE).into());
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.unwrap(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
#[cfg(feature = "metadata")]
|
#[cfg(feature = "metadata")]
|
||||||
input_type_names.push(arg_name);
|
input_type_names.push(arg_name);
|
||||||
input_type_exprs.push(
|
input_type_exprs.push(
|
||||||
@ -877,6 +866,7 @@ impl ExportedFn {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)] fn is_method_call(&self) -> bool { #is_method_call }
|
#[inline(always)] fn is_method_call(&self) -> bool { #is_method_call }
|
||||||
|
#[inline(always)] fn is_pure(&self) -> bool { #is_pure }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -285,6 +285,7 @@ mod generate_tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)] fn is_method_call(&self) -> bool { false }
|
#[inline(always)] fn is_method_call(&self) -> bool { false }
|
||||||
|
#[inline(always)] fn is_pure(&self) -> bool { true }
|
||||||
}
|
}
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
@ -323,6 +324,7 @@ mod generate_tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)] fn is_method_call(&self) -> bool { false }
|
#[inline(always)] fn is_method_call(&self) -> bool { false }
|
||||||
|
#[inline(always)] fn is_pure(&self) -> bool { true }
|
||||||
}
|
}
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
@ -361,6 +363,7 @@ mod generate_tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)] fn is_method_call(&self) -> bool { false }
|
#[inline(always)] fn is_method_call(&self) -> bool { false }
|
||||||
|
#[inline(always)] fn is_pure(&self) -> bool { true }
|
||||||
}
|
}
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
@ -401,6 +404,7 @@ mod generate_tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)] fn is_method_call(&self) -> bool { false }
|
#[inline(always)] fn is_method_call(&self) -> bool { false }
|
||||||
|
#[inline(always)] fn is_pure(&self) -> bool { true }
|
||||||
}
|
}
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
@ -434,6 +438,7 @@ mod generate_tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)] fn is_method_call(&self) -> bool { false }
|
#[inline(always)] fn is_method_call(&self) -> bool { false }
|
||||||
|
#[inline(always)] fn is_pure(&self) -> bool { true }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -467,6 +472,7 @@ mod generate_tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)] fn is_method_call(&self) -> bool { false }
|
#[inline(always)] fn is_method_call(&self) -> bool { false }
|
||||||
|
#[inline(always)] fn is_pure(&self) -> bool { true }
|
||||||
}
|
}
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
@ -500,15 +506,13 @@ mod generate_tests {
|
|||||||
impl PluginFunction for Token {
|
impl PluginFunction for Token {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
|
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
|
||||||
if args[0usize].is_read_only() {
|
|
||||||
return Err(EvalAltResult::ErrorAssignmentToConstant("x".to_string(), Position::NONE).into());
|
|
||||||
}
|
|
||||||
let arg1 = mem::take(args[1usize]).cast::<usize>();
|
let arg1 = mem::take(args[1usize]).cast::<usize>();
|
||||||
let arg0 = &mut args[0usize].write_lock::<usize>().unwrap();
|
let arg0 = &mut args[0usize].write_lock::<usize>().unwrap();
|
||||||
Ok(Dynamic::from(increment(arg0, arg1)))
|
Ok(Dynamic::from(increment(arg0, arg1)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)] fn is_method_call(&self) -> bool { true }
|
#[inline(always)] fn is_method_call(&self) -> bool { true }
|
||||||
|
#[inline(always)] fn is_pure(&self) -> bool { false }
|
||||||
}
|
}
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
@ -548,6 +552,7 @@ mod generate_tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)] fn is_method_call(&self) -> bool { false }
|
#[inline(always)] fn is_method_call(&self) -> bool { false }
|
||||||
|
#[inline(always)] fn is_pure(&self) -> bool { true }
|
||||||
}
|
}
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
@ -390,6 +390,7 @@ mod generate_tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)] fn is_method_call(&self) -> bool { false }
|
#[inline(always)] fn is_method_call(&self) -> bool { false }
|
||||||
|
#[inline(always)] fn is_pure(&self) -> bool { true }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -467,6 +468,7 @@ mod generate_tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)] fn is_method_call(&self) -> bool { false }
|
#[inline(always)] fn is_method_call(&self) -> bool { false }
|
||||||
|
#[inline(always)] fn is_pure(&self) -> bool { true }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -525,6 +527,7 @@ mod generate_tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)] fn is_method_call(&self) -> bool { false }
|
#[inline(always)] fn is_method_call(&self) -> bool { false }
|
||||||
|
#[inline(always)] fn is_pure(&self) -> bool { true }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -582,6 +585,7 @@ mod generate_tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)] fn is_method_call(&self) -> bool { false }
|
#[inline(always)] fn is_method_call(&self) -> bool { false }
|
||||||
|
#[inline(always)] fn is_pure(&self) -> bool { true }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -653,6 +657,7 @@ mod generate_tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)] fn is_method_call(&self) -> bool { false }
|
#[inline(always)] fn is_method_call(&self) -> bool { false }
|
||||||
|
#[inline(always)] fn is_pure(&self) -> bool { true }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
@ -672,6 +677,7 @@ mod generate_tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)] fn is_method_call(&self) -> bool { false }
|
#[inline(always)] fn is_method_call(&self) -> bool { false }
|
||||||
|
#[inline(always)] fn is_pure(&self) -> bool { true }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -730,6 +736,7 @@ mod generate_tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)] fn is_method_call(&self) -> bool { false }
|
#[inline(always)] fn is_method_call(&self) -> bool { false }
|
||||||
|
#[inline(always)] fn is_pure(&self) -> bool { true }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -795,6 +802,7 @@ mod generate_tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)] fn is_method_call(&self) -> bool { false }
|
#[inline(always)] fn is_method_call(&self) -> bool { false }
|
||||||
|
#[inline(always)] fn is_pure(&self) -> bool { true }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -864,14 +872,12 @@ mod generate_tests {
|
|||||||
impl PluginFunction for get_mystic_number_token {
|
impl PluginFunction for get_mystic_number_token {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
|
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
|
||||||
if args[0usize].is_read_only() {
|
|
||||||
return Err(EvalAltResult::ErrorAssignmentToConstant("x".to_string(), Position::NONE).into());
|
|
||||||
}
|
|
||||||
let arg0 = &mut args[0usize].write_lock::<Hello>().unwrap();
|
let arg0 = &mut args[0usize].write_lock::<Hello>().unwrap();
|
||||||
Ok(Dynamic::from(get_mystic_number(arg0)))
|
Ok(Dynamic::from(get_mystic_number(arg0)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)] fn is_method_call(&self) -> bool { true }
|
#[inline(always)] fn is_method_call(&self) -> bool { true }
|
||||||
|
#[inline(always)] fn is_pure(&self) -> bool { false }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1080,6 +1086,7 @@ mod generate_tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)] fn is_method_call(&self) -> bool { false }
|
#[inline(always)] fn is_method_call(&self) -> bool { false }
|
||||||
|
#[inline(always)] fn is_pure(&self) -> bool { true }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1170,6 +1177,7 @@ mod generate_tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)] fn is_method_call(&self) -> bool { false }
|
#[inline(always)] fn is_method_call(&self) -> bool { false }
|
||||||
|
#[inline(always)] fn is_pure(&self) -> bool { true }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1227,6 +1235,7 @@ mod generate_tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)] fn is_method_call(&self) -> bool { false }
|
#[inline(always)] fn is_method_call(&self) -> bool { false }
|
||||||
|
#[inline(always)] fn is_pure(&self) -> bool { true }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1286,6 +1295,7 @@ mod generate_tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)] fn is_method_call(&self) -> bool { true }
|
#[inline(always)] fn is_method_call(&self) -> bool { true }
|
||||||
|
#[inline(always)] fn is_pure(&self) -> bool { true }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1338,14 +1348,12 @@ mod generate_tests {
|
|||||||
impl PluginFunction for increment_token {
|
impl PluginFunction for increment_token {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
|
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
|
||||||
if args[0usize].is_read_only() {
|
|
||||||
return Err(EvalAltResult::ErrorAssignmentToConstant("x".to_string(), Position::NONE).into());
|
|
||||||
}
|
|
||||||
let arg0 = &mut args[0usize].write_lock::<FLOAT>().unwrap();
|
let arg0 = &mut args[0usize].write_lock::<FLOAT>().unwrap();
|
||||||
Ok(Dynamic::from(increment(arg0)))
|
Ok(Dynamic::from(increment(arg0)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)] fn is_method_call(&self) -> bool { true }
|
#[inline(always)] fn is_method_call(&self) -> bool { true }
|
||||||
|
#[inline(always)] fn is_pure(&self) -> bool { false }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1401,14 +1409,12 @@ mod generate_tests {
|
|||||||
impl PluginFunction for increment_token {
|
impl PluginFunction for increment_token {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
|
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
|
||||||
if args[0usize].is_read_only() {
|
|
||||||
return Err(EvalAltResult::ErrorAssignmentToConstant("x".to_string(), Position::NONE).into());
|
|
||||||
}
|
|
||||||
let arg0 = &mut args[0usize].write_lock::<FLOAT>().unwrap();
|
let arg0 = &mut args[0usize].write_lock::<FLOAT>().unwrap();
|
||||||
Ok(Dynamic::from(increment(arg0)))
|
Ok(Dynamic::from(increment(arg0)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)] fn is_method_call(&self) -> bool { true }
|
#[inline(always)] fn is_method_call(&self) -> bool { true }
|
||||||
|
#[inline(always)] fn is_pure(&self) -> bool { false }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
@ -1487,14 +1493,12 @@ mod generate_tests {
|
|||||||
impl PluginFunction for increment_token {
|
impl PluginFunction for increment_token {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
|
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
|
||||||
if args[0usize].is_read_only() {
|
|
||||||
return Err(EvalAltResult::ErrorAssignmentToConstant("x".to_string(), Position::NONE).into());
|
|
||||||
}
|
|
||||||
let arg0 = &mut args[0usize].write_lock::<FLOAT>().unwrap();
|
let arg0 = &mut args[0usize].write_lock::<FLOAT>().unwrap();
|
||||||
Ok(Dynamic::from(increment(arg0)))
|
Ok(Dynamic::from(increment(arg0)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)] fn is_method_call(&self) -> bool { true }
|
#[inline(always)] fn is_method_call(&self) -> bool { true }
|
||||||
|
#[inline(always)] fn is_pure(&self) -> bool { false }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
@ -1574,14 +1578,12 @@ mod generate_tests {
|
|||||||
impl PluginFunction for int_foo_token {
|
impl PluginFunction for int_foo_token {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
|
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
|
||||||
if args[0usize].is_read_only() {
|
|
||||||
return Err(EvalAltResult::ErrorAssignmentToConstant("x".to_string(), Position::NONE).into());
|
|
||||||
}
|
|
||||||
let arg0 = &mut args[0usize].write_lock::<u64>().unwrap();
|
let arg0 = &mut args[0usize].write_lock::<u64>().unwrap();
|
||||||
Ok(Dynamic::from(int_foo(arg0)))
|
Ok(Dynamic::from(int_foo(arg0)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)] fn is_method_call(&self) -> bool { true }
|
#[inline(always)] fn is_method_call(&self) -> bool { true }
|
||||||
|
#[inline(always)] fn is_pure(&self) -> bool { false }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1638,14 +1640,12 @@ mod generate_tests {
|
|||||||
impl PluginFunction for int_foo_token {
|
impl PluginFunction for int_foo_token {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
|
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
|
||||||
if args[0usize].is_read_only() {
|
|
||||||
return Err(EvalAltResult::ErrorAssignmentToConstant("x".to_string(), Position::NONE).into());
|
|
||||||
}
|
|
||||||
let arg0 = &mut args[0usize].write_lock::<u64>().unwrap();
|
let arg0 = &mut args[0usize].write_lock::<u64>().unwrap();
|
||||||
Ok(Dynamic::from(int_foo(arg0)))
|
Ok(Dynamic::from(int_foo(arg0)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)] fn is_method_call(&self) -> bool { true }
|
#[inline(always)] fn is_method_call(&self) -> bool { true }
|
||||||
|
#[inline(always)] fn is_pure(&self) -> bool { false }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1699,15 +1699,13 @@ mod generate_tests {
|
|||||||
impl PluginFunction for int_foo_token {
|
impl PluginFunction for int_foo_token {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
|
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
|
||||||
if args[0usize].is_read_only() {
|
|
||||||
return Err(EvalAltResult::ErrorAssignmentToConstant("x".to_string(), Position::NONE).into());
|
|
||||||
}
|
|
||||||
let arg1 = mem::take(args[1usize]).cast::<u64>();
|
let arg1 = mem::take(args[1usize]).cast::<u64>();
|
||||||
let arg0 = &mut args[0usize].write_lock::<u64>().unwrap();
|
let arg0 = &mut args[0usize].write_lock::<u64>().unwrap();
|
||||||
Ok(Dynamic::from(int_foo(arg0, arg1)))
|
Ok(Dynamic::from(int_foo(arg0, arg1)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)] fn is_method_call(&self) -> bool { true }
|
#[inline(always)] fn is_method_call(&self) -> bool { true }
|
||||||
|
#[inline(always)] fn is_pure(&self) -> bool { false }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1764,15 +1762,13 @@ mod generate_tests {
|
|||||||
impl PluginFunction for int_foo_token {
|
impl PluginFunction for int_foo_token {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
|
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
|
||||||
if args[0usize].is_read_only() {
|
|
||||||
return Err(EvalAltResult::ErrorAssignmentToConstant("x".to_string(), Position::NONE).into());
|
|
||||||
}
|
|
||||||
let arg1 = mem::take(args[1usize]).cast::<u64>();
|
let arg1 = mem::take(args[1usize]).cast::<u64>();
|
||||||
let arg0 = &mut args[0usize].write_lock::<u64>().unwrap();
|
let arg0 = &mut args[0usize].write_lock::<u64>().unwrap();
|
||||||
Ok(Dynamic::from(int_foo(arg0, arg1)))
|
Ok(Dynamic::from(int_foo(arg0, arg1)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)] fn is_method_call(&self) -> bool { true }
|
#[inline(always)] fn is_method_call(&self) -> bool { true }
|
||||||
|
#[inline(always)] fn is_pure(&self) -> bool { false }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1826,15 +1822,13 @@ mod generate_tests {
|
|||||||
impl PluginFunction for get_by_index_token {
|
impl PluginFunction for get_by_index_token {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
|
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
|
||||||
if args[0usize].is_read_only() {
|
|
||||||
return Err(EvalAltResult::ErrorAssignmentToConstant("x".to_string(), Position::NONE).into());
|
|
||||||
}
|
|
||||||
let arg1 = mem::take(args[1usize]).cast::<u64>();
|
let arg1 = mem::take(args[1usize]).cast::<u64>();
|
||||||
let arg0 = &mut args[0usize].write_lock::<MyCollection>().unwrap();
|
let arg0 = &mut args[0usize].write_lock::<MyCollection>().unwrap();
|
||||||
Ok(Dynamic::from(get_by_index(arg0, arg1)))
|
Ok(Dynamic::from(get_by_index(arg0, arg1)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)] fn is_method_call(&self) -> bool { true }
|
#[inline(always)] fn is_method_call(&self) -> bool { true }
|
||||||
|
#[inline(always)] fn is_pure(&self) -> bool { false }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1896,15 +1890,13 @@ mod generate_tests {
|
|||||||
impl PluginFunction for get_by_index_token {
|
impl PluginFunction for get_by_index_token {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
|
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
|
||||||
if args[0usize].is_read_only() {
|
|
||||||
return Err(EvalAltResult::ErrorAssignmentToConstant("x".to_string(), Position::NONE).into());
|
|
||||||
}
|
|
||||||
let arg1 = mem::take(args[1usize]).cast::<u64>();
|
let arg1 = mem::take(args[1usize]).cast::<u64>();
|
||||||
let arg0 = &mut args[0usize].write_lock::<MyCollection>().unwrap();
|
let arg0 = &mut args[0usize].write_lock::<MyCollection>().unwrap();
|
||||||
Ok(Dynamic::from(get_by_index(arg0, arg1)))
|
Ok(Dynamic::from(get_by_index(arg0, arg1)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)] fn is_method_call(&self) -> bool { true }
|
#[inline(always)] fn is_method_call(&self) -> bool { true }
|
||||||
|
#[inline(always)] fn is_pure(&self) -> bool { false }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1961,15 +1953,13 @@ mod generate_tests {
|
|||||||
impl PluginFunction for get_by_index_token {
|
impl PluginFunction for get_by_index_token {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
|
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
|
||||||
if args[0usize].is_read_only() {
|
|
||||||
return Err(EvalAltResult::ErrorAssignmentToConstant("x".to_string(), Position::NONE).into());
|
|
||||||
}
|
|
||||||
let arg1 = mem::take(args[1usize]).cast::<u64>();
|
let arg1 = mem::take(args[1usize]).cast::<u64>();
|
||||||
let arg0 = &mut args[0usize].write_lock::<MyCollection>().unwrap();
|
let arg0 = &mut args[0usize].write_lock::<MyCollection>().unwrap();
|
||||||
Ok(Dynamic::from(get_by_index(arg0, arg1)))
|
Ok(Dynamic::from(get_by_index(arg0, arg1)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)] fn is_method_call(&self) -> bool { true }
|
#[inline(always)] fn is_method_call(&self) -> bool { true }
|
||||||
|
#[inline(always)] fn is_pure(&self) -> bool { false }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -2023,9 +2013,6 @@ mod generate_tests {
|
|||||||
impl PluginFunction for set_by_index_token {
|
impl PluginFunction for set_by_index_token {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
|
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
|
||||||
if args[0usize].is_read_only() {
|
|
||||||
return Err(EvalAltResult::ErrorAssignmentToConstant("x".to_string(), Position::NONE).into());
|
|
||||||
}
|
|
||||||
let arg1 = mem::take(args[1usize]).cast::<u64>();
|
let arg1 = mem::take(args[1usize]).cast::<u64>();
|
||||||
let arg2 = mem::take(args[2usize]).cast::<FLOAT>();
|
let arg2 = mem::take(args[2usize]).cast::<FLOAT>();
|
||||||
let arg0 = &mut args[0usize].write_lock::<MyCollection>().unwrap();
|
let arg0 = &mut args[0usize].write_lock::<MyCollection>().unwrap();
|
||||||
@ -2033,6 +2020,7 @@ mod generate_tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)] fn is_method_call(&self) -> bool { true }
|
#[inline(always)] fn is_method_call(&self) -> bool { true }
|
||||||
|
#[inline(always)] fn is_pure(&self) -> bool { false }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -2089,9 +2077,6 @@ mod generate_tests {
|
|||||||
impl PluginFunction for set_by_index_token {
|
impl PluginFunction for set_by_index_token {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
|
fn call(&self, context: NativeCallContext, args: &mut [&mut Dynamic]) -> RhaiResult {
|
||||||
if args[0usize].is_read_only() {
|
|
||||||
return Err(EvalAltResult::ErrorAssignmentToConstant("x".to_string(), Position::NONE).into());
|
|
||||||
}
|
|
||||||
let arg1 = mem::take(args[1usize]).cast::<u64>();
|
let arg1 = mem::take(args[1usize]).cast::<u64>();
|
||||||
let arg2 = mem::take(args[2usize]).cast::<FLOAT>();
|
let arg2 = mem::take(args[2usize]).cast::<FLOAT>();
|
||||||
let arg0 = &mut args[0usize].write_lock::<MyCollection>().unwrap();
|
let arg0 = &mut args[0usize].write_lock::<MyCollection>().unwrap();
|
||||||
@ -2099,6 +2084,7 @@ mod generate_tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)] fn is_method_call(&self) -> bool { true }
|
#[inline(always)] fn is_method_call(&self) -> bool { true }
|
||||||
|
#[inline(always)] fn is_pure(&self) -> bool { false }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -38,7 +38,7 @@ fn main() -> Result<(), Box<EvalAltResult>> {
|
|||||||
engine
|
engine
|
||||||
.gen_fn_signatures(false)
|
.gen_fn_signatures(false)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.for_each(|func| println!("{}", func));
|
.for_each(|func| println!("{func}"));
|
||||||
|
|
||||||
println!();
|
println!();
|
||||||
}
|
}
|
||||||
@ -51,7 +51,7 @@ fn main() -> Result<(), Box<EvalAltResult>> {
|
|||||||
",
|
",
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
println!("{:?}", result);
|
println!("{result:?}");
|
||||||
|
|
||||||
let result = engine.eval::<TestStruct>(
|
let result = engine.eval::<TestStruct>(
|
||||||
"
|
"
|
||||||
@ -61,7 +61,7 @@ fn main() -> Result<(), Box<EvalAltResult>> {
|
|||||||
",
|
",
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
println!("{:?}", result);
|
println!("{result:?}");
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ fn main() -> Result<(), Box<EvalAltResult>> {
|
|||||||
let r2 = func(1, 2);
|
let r2 = func(1, 2);
|
||||||
let r3 = func(1, 2);
|
let r3 = func(1, 2);
|
||||||
|
|
||||||
println!("The Answers: {}, {}, {}", r1, r2, r3); // prints 40, 42, 44
|
println!("The Answers: {r1}, {r2}, {r3}"); // prints 40, 42, 44
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -67,7 +67,7 @@ fn main() -> Result<(), Box<EvalAltResult>> {
|
|||||||
engine
|
engine
|
||||||
.gen_fn_signatures(false)
|
.gen_fn_signatures(false)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.for_each(|func| println!("{}", func));
|
.for_each(|func| println!("{func}"));
|
||||||
|
|
||||||
println!();
|
println!();
|
||||||
}
|
}
|
||||||
@ -89,7 +89,7 @@ fn main() -> Result<(), Box<EvalAltResult>> {
|
|||||||
",
|
",
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
println!("result: {}", result); // prints 1085764
|
println!("result: {result}"); // prints 1085764
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ fn main() -> Result<(), Box<EvalAltResult>> {
|
|||||||
engine
|
engine
|
||||||
.gen_fn_signatures(false)
|
.gen_fn_signatures(false)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.for_each(|func| println!("{}", func));
|
.for_each(|func| println!("{func}"));
|
||||||
|
|
||||||
println!();
|
println!();
|
||||||
}
|
}
|
||||||
@ -62,7 +62,7 @@ fn main() -> Result<(), Box<EvalAltResult>> {
|
|||||||
",
|
",
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
println!("result: {}", result); // prints 1085764
|
println!("result: {result}"); // prints 1085764
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -78,12 +78,12 @@ pub fn main() {
|
|||||||
scope.push_constant("MY_CONSTANT", 42_i64);
|
scope.push_constant("MY_CONSTANT", 42_i64);
|
||||||
|
|
||||||
// Compile the handler script.
|
// Compile the handler script.
|
||||||
println!("> Loading script file: {}", path);
|
println!("> Loading script file: {path}");
|
||||||
|
|
||||||
let ast = match engine.compile_file_with_scope(&mut scope, path.into()) {
|
let ast = match engine.compile_file_with_scope(&mut scope, path.into()) {
|
||||||
Ok(ast) => ast,
|
Ok(ast) => ast,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
eprintln!("! Error: {}", err);
|
eprintln!("! Error: {err}");
|
||||||
println!("Cannot continue. Bye!");
|
println!("Cannot continue. Bye!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -101,7 +101,7 @@ pub fn main() {
|
|||||||
let result = engine.call_fn_raw(&mut scope, &ast, false, true, "init", Some(&mut states), []);
|
let result = engine.call_fn_raw(&mut scope, &ast, false, true, "init", Some(&mut states), []);
|
||||||
|
|
||||||
if let Err(err) = result {
|
if let Err(err) = result {
|
||||||
eprintln!("! {}", err)
|
eprintln!("! {err}")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create handler instance
|
// Create handler instance
|
||||||
@ -152,7 +152,7 @@ pub fn main() {
|
|||||||
engine.call_fn_raw(scope, ast, false, true, event, this_ptr, [arg.into()]);
|
engine.call_fn_raw(scope, ast, false, true, event, this_ptr, [arg.into()]);
|
||||||
|
|
||||||
if let Err(err) = result {
|
if let Err(err) = result {
|
||||||
eprintln!("! {}", err)
|
eprintln!("! {err}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,7 +67,7 @@ pub fn main() {
|
|||||||
scope.push_constant("MY_CONSTANT", 42_i64);
|
scope.push_constant("MY_CONSTANT", 42_i64);
|
||||||
|
|
||||||
// Compile the handler script.
|
// Compile the handler script.
|
||||||
println!("> Loading script file: {}", path);
|
println!("> Loading script file: {path}");
|
||||||
|
|
||||||
let ast = match engine.compile_file_with_scope(&mut scope, path.into()) {
|
let ast = match engine.compile_file_with_scope(&mut scope, path.into()) {
|
||||||
Ok(ast) => ast,
|
Ok(ast) => ast,
|
||||||
@ -89,7 +89,7 @@ pub fn main() {
|
|||||||
let result = engine.call_fn_raw(&mut scope, &ast, false, false, "init", None, []);
|
let result = engine.call_fn_raw(&mut scope, &ast, false, false, "init", None, []);
|
||||||
|
|
||||||
if let Err(err) = result {
|
if let Err(err) = result {
|
||||||
eprintln!("! {}", err)
|
eprintln!("! {err}")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create handler instance
|
// Create handler instance
|
||||||
@ -127,7 +127,7 @@ pub fn main() {
|
|||||||
let result = engine.call_fn::<()>(scope, ast, event, (arg.to_string(),));
|
let result = engine.call_fn::<()>(scope, ast, event, (arg.to_string(),));
|
||||||
|
|
||||||
if let Err(err) = result {
|
if let Err(err) = result {
|
||||||
eprintln!("! {}", err)
|
eprintln!("! {err}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -81,12 +81,12 @@ pub fn main() {
|
|||||||
scope.push("state", states);
|
scope.push("state", states);
|
||||||
|
|
||||||
// Compile the handler script.
|
// Compile the handler script.
|
||||||
println!("> Loading script file: {}", path);
|
println!("> Loading script file: {path}");
|
||||||
|
|
||||||
let ast = match engine.compile_file_with_scope(&mut scope, path.into()) {
|
let ast = match engine.compile_file_with_scope(&mut scope, path.into()) {
|
||||||
Ok(ast) => ast,
|
Ok(ast) => ast,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
eprintln!("! Error: {}", err);
|
eprintln!("! Error: {err}");
|
||||||
println!("Cannot continue. Bye!");
|
println!("Cannot continue. Bye!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -103,7 +103,7 @@ pub fn main() {
|
|||||||
let result = engine.call_fn::<()>(&mut scope, &ast, "init", ());
|
let result = engine.call_fn::<()>(&mut scope, &ast, "init", ());
|
||||||
|
|
||||||
if let Err(err) = result {
|
if let Err(err) = result {
|
||||||
eprintln!("! {}", err)
|
eprintln!("! {err}")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create handler instance
|
// Create handler instance
|
||||||
@ -141,7 +141,7 @@ pub fn main() {
|
|||||||
let result = engine.call_fn::<()>(scope, ast, event, (arg.to_string(),));
|
let result = engine.call_fn::<()>(scope, ast, event, (arg.to_string(),));
|
||||||
|
|
||||||
if let Err(err) = result {
|
if let Err(err) = result {
|
||||||
eprintln!("! {}", err)
|
eprintln!("! {err}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ fn main() -> Result<(), Box<EvalAltResult>> {
|
|||||||
|
|
||||||
let result = engine.eval::<i64>("40 + 2")?;
|
let result = engine.eval::<i64>("40 + 2")?;
|
||||||
|
|
||||||
println!("The Answer: {}", result); // prints 42
|
println!("The Answer: {result}"); // prints 42
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ fn main() -> Result<(), Box<EvalAltResult>> {
|
|||||||
for _ in 0..10 {
|
for _ in 0..10 {
|
||||||
let result = engine.eval_with_scope::<i64>(&mut scope, "x += 1; x")?;
|
let result = engine.eval_with_scope::<i64>(&mut scope, "x += 1; x")?;
|
||||||
|
|
||||||
println!("result: {}", result);
|
println!("result: {result}");
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("x = {}", scope.get_value::<i64>("x").unwrap());
|
println!("x = {}", scope.get_value::<i64>("x").unwrap());
|
||||||
|
@ -36,13 +36,13 @@ fn main() {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
println!("Source struct: {:#?}", x);
|
println!("Source struct: {x:#?}");
|
||||||
|
|
||||||
// Convert the 'MyStruct' into a 'Dynamic'
|
// Convert the 'MyStruct' into a 'Dynamic'
|
||||||
let map: Dynamic = to_dynamic(x).unwrap();
|
let map: Dynamic = to_dynamic(x).unwrap();
|
||||||
|
|
||||||
assert!(map.is::<Map>());
|
assert!(map.is::<Map>());
|
||||||
println!("Serialized to Dynamic: {:#?}", map);
|
println!("Serialized to Dynamic: {map:#?}");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn de() {
|
pub fn de() {
|
||||||
@ -60,7 +60,7 @@ fn main() {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
println!("Source Dynamic: {:#?}", result);
|
println!("Source Dynamic: {result:#?}");
|
||||||
|
|
||||||
// Convert the 'Dynamic' object map into 'MyStruct'
|
// Convert the 'Dynamic' object map into 'MyStruct'
|
||||||
let x: MyStruct = from_dynamic(&result).unwrap();
|
let x: MyStruct = from_dynamic(&result).unwrap();
|
||||||
@ -77,7 +77,7 @@ fn main() {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
println!("Deserialized to struct: {:#?}", x);
|
println!("Deserialized to struct: {x:#?}");
|
||||||
}
|
}
|
||||||
|
|
||||||
ser();
|
ser();
|
||||||
|
@ -13,7 +13,7 @@ fn main() -> Result<(), Box<EvalAltResult>> {
|
|||||||
|
|
||||||
let result = engine.eval::<i64>("add(40, 2)")?;
|
let result = engine.eval::<i64>("add(40, 2)")?;
|
||||||
|
|
||||||
println!("Answer: {}", result); // prints 42
|
println!("Answer: {result}"); // prints 42
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -37,10 +37,10 @@ fn main() -> Result<(), Box<EvalAltResult>> {
|
|||||||
.register_fn("index_of", find_substring)
|
.register_fn("index_of", find_substring)
|
||||||
// Register string functions using closures
|
// Register string functions using closures
|
||||||
.register_fn("display", |label: &str, value: i64| {
|
.register_fn("display", |label: &str, value: i64| {
|
||||||
println!("{}: {}", label, value)
|
println!("{label}: {value}")
|
||||||
})
|
})
|
||||||
.register_fn("display", |label: ImmutableString, value: &str| {
|
.register_fn("display", |label: ImmutableString, value: &str| {
|
||||||
println!(r#"{}: "{}""#, label, value) // Quote the input string
|
println!(r#"{label}: "{value}""#) // Quote the input string
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut scope = Scope::new();
|
let mut scope = Scope::new();
|
||||||
|
@ -60,7 +60,7 @@ fn main() {
|
|||||||
let mut value: i64 = 0;
|
let mut value: i64 = 0;
|
||||||
|
|
||||||
while value < 10 {
|
while value < 10 {
|
||||||
println!("Value: {}", value);
|
println!("Value: {value}");
|
||||||
// Send value to script
|
// Send value to script
|
||||||
tx_master.send(value).unwrap();
|
tx_master.send(value).unwrap();
|
||||||
// Receive value from script
|
// Receive value from script
|
||||||
|
@ -10,9 +10,9 @@ use crate::{
|
|||||||
reify, Dynamic, Engine, EvalContext, Identifier, ImmutableString, LexError, Position,
|
reify, Dynamic, Engine, EvalContext, Identifier, ImmutableString, LexError, Position,
|
||||||
RhaiResult, StaticVec,
|
RhaiResult, StaticVec,
|
||||||
};
|
};
|
||||||
use std::ops::Deref;
|
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
|
use std::{borrow::Borrow, ops::Deref};
|
||||||
|
|
||||||
/// Collection of special markers for custom syntax definition.
|
/// Collection of special markers for custom syntax definition.
|
||||||
pub mod markers {
|
pub mod markers {
|
||||||
@ -145,6 +145,14 @@ impl Expression<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Borrow<Expr> for Expression<'_> {
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
fn borrow(&self) -> &Expr {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl AsRef<Expr> for Expression<'_> {
|
impl AsRef<Expr> for Expression<'_> {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
@ -440,18 +440,16 @@ impl Module {
|
|||||||
}
|
}
|
||||||
first = false;
|
first = false;
|
||||||
|
|
||||||
if f.access == FnAccess::Private {
|
if f.access != FnAccess::Private {
|
||||||
continue;
|
#[cfg(not(feature = "no_custom_syntax"))]
|
||||||
|
let operator = def.engine.custom_keywords.contains_key(&f.name)
|
||||||
|
|| (!f.name.contains('$') && !is_valid_function_name(&f.name));
|
||||||
|
|
||||||
|
#[cfg(feature = "no_custom_syntax")]
|
||||||
|
let operator = !f.name.contains('$') && !is_valid_function_name(&f.name);
|
||||||
|
|
||||||
|
f.write_definition(writer, def, operator)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_custom_syntax"))]
|
|
||||||
let operator = def.engine.custom_keywords.contains_key(&f.name)
|
|
||||||
|| (!f.name.contains('$') && !is_valid_function_name(&f.name));
|
|
||||||
|
|
||||||
#[cfg(feature = "no_custom_syntax")]
|
|
||||||
let operator = !f.name.contains('$') && !is_valid_function_name(&f.name);
|
|
||||||
|
|
||||||
f.write_definition(writer, def, operator)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -555,7 +553,6 @@ fn def_type_name<'a>(ty: &'a str, engine: &'a Engine) -> Cow<'a, str> {
|
|||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
let ty = ty.replace(type_name::<crate::Map>(), "Map");
|
let ty = ty.replace(type_name::<crate::Map>(), "Map");
|
||||||
|
|
||||||
#[cfg(not(feature = "no_std"))]
|
|
||||||
#[cfg(not(feature = "no_time"))]
|
#[cfg(not(feature = "no_time"))]
|
||||||
let ty = ty.replace(type_name::<crate::Instant>(), "Instant");
|
let ty = ty.replace(type_name::<crate::Instant>(), "Instant");
|
||||||
|
|
||||||
|
@ -166,10 +166,7 @@ pub fn format_map_as_json(map: &Map) -> String {
|
|||||||
|
|
||||||
if let Some(val) = value.read_lock::<Map>() {
|
if let Some(val) = value.read_lock::<Map>() {
|
||||||
result.push_str(&format_map_as_json(&*val));
|
result.push_str(&format_map_as_json(&*val));
|
||||||
continue;
|
} else if value.is::<()>() {
|
||||||
}
|
|
||||||
|
|
||||||
if value.is::<()>() {
|
|
||||||
result.push_str("null");
|
result.push_str("null");
|
||||||
} else {
|
} else {
|
||||||
write!(result, "{:?}", value).unwrap();
|
write!(result, "{:?}", value).unwrap();
|
||||||
|
@ -35,9 +35,6 @@ pub mod definitions;
|
|||||||
|
|
||||||
use crate::{Dynamic, Engine, Identifier};
|
use crate::{Dynamic, Engine, Identifier};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_custom_syntax"))]
|
|
||||||
use crate::{engine::Precedence, tokenizer::Token};
|
|
||||||
|
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
|
|
||||||
@ -150,8 +147,10 @@ impl Engine {
|
|||||||
keyword: impl AsRef<str>,
|
keyword: impl AsRef<str>,
|
||||||
precedence: u8,
|
precedence: u8,
|
||||||
) -> Result<&mut Self, String> {
|
) -> Result<&mut Self, String> {
|
||||||
let precedence =
|
use crate::tokenizer::Token;
|
||||||
Precedence::new(precedence).ok_or_else(|| "precedence cannot be zero".to_string())?;
|
|
||||||
|
let precedence = crate::engine::Precedence::new(precedence)
|
||||||
|
.ok_or_else(|| "precedence cannot be zero".to_string())?;
|
||||||
|
|
||||||
let keyword = keyword.as_ref();
|
let keyword = keyword.as_ref();
|
||||||
|
|
||||||
@ -215,3 +214,71 @@ impl Engine {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "unchecked")]
|
||||||
|
impl Engine {
|
||||||
|
/// The maximum levels of function calls allowed for a script.
|
||||||
|
///
|
||||||
|
/// Always returns [`usize::MAX`] under `unchecked`.
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn max_call_levels(&self) -> usize {
|
||||||
|
usize::MAX
|
||||||
|
}
|
||||||
|
/// The maximum number of operations allowed for a script to run (0 for unlimited).
|
||||||
|
///
|
||||||
|
/// Always returns zero under `unchecked`.
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn max_operations(&self) -> u64 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
/// The maximum number of imported [modules][crate::Module] allowed for a script.
|
||||||
|
///
|
||||||
|
/// Always returns [`usize::MAX`] under `unchecked`.
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn max_modules(&self) -> usize {
|
||||||
|
usize::MAX
|
||||||
|
}
|
||||||
|
/// The depth limit for expressions (0 for unlimited).
|
||||||
|
///
|
||||||
|
/// Always returns zero under `unchecked`.
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn max_expr_depth(&self) -> usize {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
/// The depth limit for expressions in functions (0 for unlimited).
|
||||||
|
///
|
||||||
|
/// Always returns zero under `unchecked`.
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn max_function_expr_depth(&self) -> usize {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
/// The maximum length of [strings][crate::ImmutableString] (0 for unlimited).
|
||||||
|
///
|
||||||
|
/// Always returns zero under `unchecked`.
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn max_string_size(&self) -> usize {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
/// The maximum length of [arrays][crate::Array] (0 for unlimited).
|
||||||
|
///
|
||||||
|
/// Always returns zero under `unchecked`.
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn max_array_size(&self) -> usize {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
/// The maximum size of [object maps][crate::Map] (0 for unlimited).
|
||||||
|
///
|
||||||
|
/// Always returns zero under `unchecked`.
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn max_map_size(&self) -> usize {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -44,7 +44,6 @@ fn map_std_type_name(name: &str, shorthands: bool) -> &str {
|
|||||||
if name == type_name::<crate::Map>() || name == "Map" {
|
if name == type_name::<crate::Map>() || name == "Map" {
|
||||||
return if shorthands { "map" } else { "Map" };
|
return if shorthands { "map" } else { "Map" };
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "no_std"))]
|
|
||||||
#[cfg(not(feature = "no_time"))]
|
#[cfg(not(feature = "no_time"))]
|
||||||
if name == type_name::<crate::Instant>() || name == "Instant" {
|
if name == type_name::<crate::Instant>() || name == "Instant" {
|
||||||
return if shorthands { "timestamp" } else { "Instant" };
|
return if shorthands { "timestamp" } else { "Instant" };
|
||||||
|
@ -5,6 +5,7 @@ use crate::{Dynamic, FnNamespace, Identifier, Position};
|
|||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
use std::{
|
use std::{
|
||||||
|
borrow::Borrow,
|
||||||
fmt,
|
fmt,
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
ops::{Add, AddAssign},
|
ops::{Add, AddAssign},
|
||||||
@ -919,6 +920,14 @@ impl<A: Into<Self>> AddAssign<A> for AST {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Borrow<[Stmt]> for AST {
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
fn borrow(&self) -> &[Stmt] {
|
||||||
|
self.statements()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl AsRef<[Stmt]> for AST {
|
impl AsRef<[Stmt]> for AST {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
@ -927,6 +936,15 @@ impl AsRef<[Stmt]> for AST {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
impl Borrow<crate::Module> for AST {
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
fn borrow(&self) -> &crate::Module {
|
||||||
|
&self.shared_lib()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
impl AsRef<crate::Module> for AST {
|
impl AsRef<crate::Module> for AST {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
@ -936,6 +954,15 @@ impl AsRef<crate::Module> for AST {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
impl Borrow<crate::Shared<crate::Module>> for AST {
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
fn borrow(&self) -> &crate::Shared<crate::Module> {
|
||||||
|
self.shared_lib()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
impl AsRef<crate::Shared<crate::Module>> for AST {
|
impl AsRef<crate::Shared<crate::Module>> for AST {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -212,19 +212,19 @@ impl fmt::Debug for FnCallExpr {
|
|||||||
if !self.namespace.is_empty() {
|
if !self.namespace.is_empty() {
|
||||||
ff.field("namespace", &self.namespace);
|
ff.field("namespace", &self.namespace);
|
||||||
}
|
}
|
||||||
if self.capture_parent_scope {
|
ff.field("hash", &self.hashes)
|
||||||
ff.field("capture_parent_scope", &self.capture_parent_scope);
|
.field("name", &self.name)
|
||||||
}
|
.field("args", &self.args);
|
||||||
if let Some(ref token) = self.operator_token {
|
if let Some(ref token) = self.operator_token {
|
||||||
ff.field("operator_token", token);
|
ff.field("operator_token", token);
|
||||||
}
|
}
|
||||||
|
if self.capture_parent_scope {
|
||||||
|
ff.field("capture_parent_scope", &self.capture_parent_scope);
|
||||||
|
}
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
if self.can_be_script {
|
if self.can_be_script {
|
||||||
ff.field("can_be_script", &self.can_be_script);
|
ff.field("can_be_script", &self.can_be_script);
|
||||||
}
|
}
|
||||||
ff.field("hash", &self.hashes)
|
|
||||||
.field("name", &self.name)
|
|
||||||
.field("args", &self.args);
|
|
||||||
ff.field("pos", &self.pos);
|
ff.field("pos", &self.pos);
|
||||||
ff.finish()
|
ff.finish()
|
||||||
}
|
}
|
||||||
@ -465,13 +465,13 @@ impl fmt::Debug for Expr {
|
|||||||
let mut display_pos = format!(" @ {:?}", self.start_position());
|
let mut display_pos = format!(" @ {:?}", self.start_position());
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
Self::DynamicConstant(value, ..) => write!(f, "{:?}", value),
|
Self::DynamicConstant(value, ..) => write!(f, "{value:?}"),
|
||||||
Self::BoolConstant(value, ..) => write!(f, "{:?}", value),
|
Self::BoolConstant(value, ..) => write!(f, "{value:?}"),
|
||||||
Self::IntegerConstant(value, ..) => write!(f, "{:?}", value),
|
Self::IntegerConstant(value, ..) => write!(f, "{value:?}"),
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
Self::FloatConstant(value, ..) => write!(f, "{:?}", value),
|
Self::FloatConstant(value, ..) => write!(f, "{value:?}"),
|
||||||
Self::CharConstant(value, ..) => write!(f, "{:?}", value),
|
Self::CharConstant(value, ..) => write!(f, "{value:?}"),
|
||||||
Self::StringConstant(value, ..) => write!(f, "{:?}", value),
|
Self::StringConstant(value, ..) => write!(f, "{value:?}"),
|
||||||
Self::Unit(..) => f.write_str("()"),
|
Self::Unit(..) => f.write_str("()"),
|
||||||
|
|
||||||
Self::InterpolatedString(x, ..) => {
|
Self::InterpolatedString(x, ..) => {
|
||||||
@ -502,10 +502,10 @@ impl fmt::Debug for Expr {
|
|||||||
f.write_str(&x.3)?;
|
f.write_str(&x.3)?;
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
if let Some(n) = x.1.index() {
|
if let Some(n) = x.1.index() {
|
||||||
write!(f, " #{}", n)?;
|
write!(f, " #{n}")?;
|
||||||
}
|
}
|
||||||
if let Some(n) = i.map_or_else(|| x.0, |n| NonZeroUsize::new(n.get() as usize)) {
|
if let Some(n) = i.map_or_else(|| x.0, |n| NonZeroUsize::new(n.get() as usize)) {
|
||||||
write!(f, " #{}", n)?;
|
write!(f, " #{n}")?;
|
||||||
}
|
}
|
||||||
f.write_str(")")
|
f.write_str(")")
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ use crate::{ImmutableString, Position};
|
|||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
use std::{
|
use std::{
|
||||||
|
borrow::Borrow,
|
||||||
fmt,
|
fmt,
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
ops::{Deref, DerefMut},
|
ops::{Deref, DerefMut},
|
||||||
@ -28,6 +29,14 @@ impl fmt::Debug for Ident {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Borrow<str> for Ident {
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
fn borrow(&self) -> &str {
|
||||||
|
self.name.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl AsRef<str> for Ident {
|
impl AsRef<str> for Ident {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
@ -37,7 +37,7 @@ impl fmt::Debug for Namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(index) = self.index {
|
if let Some(index) = self.index {
|
||||||
write!(f, "{} -> ", index)?;
|
write!(f, "{index} -> ")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
f.write_str(
|
f.write_str(
|
||||||
|
@ -7,6 +7,7 @@ use crate::{calc_fn_hash, Position, StaticVec, INT};
|
|||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
use std::{
|
use std::{
|
||||||
|
borrow::Borrow,
|
||||||
collections::BTreeMap,
|
collections::BTreeMap,
|
||||||
fmt,
|
fmt,
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
@ -184,8 +185,8 @@ impl fmt::Debug for RangeCase {
|
|||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::ExclusiveInt(r, n) => write!(f, "{}..{} => {}", r.start, r.end, n),
|
Self::ExclusiveInt(r, n) => write!(f, "{}..{} => {n}", r.start, r.end),
|
||||||
Self::InclusiveInt(r, n) => write!(f, "{}..={} => {}", *r.start(), *r.end(), n),
|
Self::InclusiveInt(r, n) => write!(f, "{}..={} => {n}", *r.start(), *r.end()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -443,6 +444,14 @@ impl DerefMut for StmtBlock {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Borrow<[Stmt]> for StmtBlock {
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
fn borrow(&self) -> &[Stmt] {
|
||||||
|
&self.block
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl AsRef<[Stmt]> for StmtBlock {
|
impl AsRef<[Stmt]> for StmtBlock {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
@ -605,7 +614,10 @@ pub enum Stmt {
|
|||||||
/// This variant does not map to any language structure. It is currently only used only to
|
/// This variant does not map to any language structure. It is currently only used only to
|
||||||
/// convert a normal variable into a shared variable when the variable is _captured_ by a closure.
|
/// convert a normal variable into a shared variable when the variable is _captured_ by a closure.
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
Share(crate::ImmutableString, Position),
|
Share(
|
||||||
|
Box<(crate::ImmutableString, Option<NonZeroUsize>)>,
|
||||||
|
Position,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Stmt {
|
impl Default for Stmt {
|
||||||
|
@ -75,7 +75,7 @@ fn print_current_source(
|
|||||||
}
|
}
|
||||||
if !src.is_empty() {
|
if !src.is_empty() {
|
||||||
// Print just a line number for imported modules
|
// Print just a line number for imported modules
|
||||||
println!("{} @ {:?}", src, pos);
|
println!("{src} @ {pos:?}");
|
||||||
} else {
|
} else {
|
||||||
// Print the current source line
|
// Print the current source line
|
||||||
print_source(lines, pos, 0, window);
|
print_source(lines, pos, 0, window);
|
||||||
@ -100,17 +100,16 @@ fn print_error(input: &str, mut err: EvalAltResult) {
|
|||||||
// Print error position
|
// Print error position
|
||||||
if pos.is_none() {
|
if pos.is_none() {
|
||||||
// No position
|
// No position
|
||||||
println!("{}", err);
|
println!("{err}");
|
||||||
} else {
|
} else {
|
||||||
// Specific position - print line text
|
// Specific position - print line text
|
||||||
println!("{}{}", line_no, lines[pos.line().unwrap() - 1]);
|
println!("{line_no}{}", lines[pos.line().unwrap() - 1]);
|
||||||
|
|
||||||
// Display position marker
|
// Display position marker
|
||||||
println!(
|
println!(
|
||||||
"{0:>1$} {2}",
|
"{0:>1$} {err}",
|
||||||
"^",
|
"^",
|
||||||
line_no.len() + pos.position().unwrap(),
|
line_no.len() + pos.position().unwrap(),
|
||||||
err
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -247,11 +246,11 @@ fn debug_callback(
|
|||||||
BreakPoint::AtPosition { .. } => (),
|
BreakPoint::AtPosition { .. } => (),
|
||||||
BreakPoint::AtFunctionName { ref name, .. }
|
BreakPoint::AtFunctionName { ref name, .. }
|
||||||
| BreakPoint::AtFunctionCall { ref name, .. } => {
|
| BreakPoint::AtFunctionCall { ref name, .. } => {
|
||||||
println!("! Call to function {}.", name)
|
println!("! Call to function {name}.")
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
BreakPoint::AtProperty { ref name, .. } => {
|
BreakPoint::AtProperty { ref name, .. } => {
|
||||||
println!("! Property {} accessed.", name)
|
println!("! Property {name} accessed.")
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
@ -311,8 +310,8 @@ fn debug_callback(
|
|||||||
println!("{:?}", node);
|
println!("{:?}", node);
|
||||||
} else {
|
} else {
|
||||||
match source {
|
match source {
|
||||||
Some(source) => println!("{:?} {} @ {:?}", node, source, pos),
|
Some(source) => println!("{node:?} {source} @ {pos:?}"),
|
||||||
None => println!("{:?} @ {:?}", node, pos),
|
None => println!("{node:?} @ {pos:?}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println!();
|
println!();
|
||||||
@ -327,7 +326,7 @@ fn debug_callback(
|
|||||||
["list" | "l", n] if n.parse::<usize>().is_ok() => {
|
["list" | "l", n] if n.parse::<usize>().is_ok() => {
|
||||||
let num = n.parse::<usize>().unwrap();
|
let num = n.parse::<usize>().unwrap();
|
||||||
if num == 0 || num > lines.len() {
|
if num == 0 || num > lines.len() {
|
||||||
eprintln!("\x1b[31mInvalid line: {}\x1b[39m", num);
|
eprintln!("\x1b[31mInvalid line: {num}\x1b[39m");
|
||||||
} else {
|
} else {
|
||||||
let pos = Position::new(num as u16, 0);
|
let pos = Position::new(num as u16, 0);
|
||||||
print_current_source(&mut context, source, pos, lines, (3, 6));
|
print_current_source(&mut context, source, pos, lines, (3, 6));
|
||||||
@ -340,17 +339,17 @@ fn debug_callback(
|
|||||||
["next" | "n"] => break Ok(DebuggerCommand::Next),
|
["next" | "n"] => break Ok(DebuggerCommand::Next),
|
||||||
["scope"] => println!("{}", context.scope()),
|
["scope"] => println!("{}", context.scope()),
|
||||||
["print" | "p", "this"] => match context.this_ptr() {
|
["print" | "p", "this"] => match context.this_ptr() {
|
||||||
Some(value) => println!("=> {:?}", value),
|
Some(value) => println!("=> {value:?}"),
|
||||||
None => println!("`this` pointer is unbound."),
|
None => println!("`this` pointer is unbound."),
|
||||||
},
|
},
|
||||||
["print" | "p", var_name] => match context.scope().get_value::<Dynamic>(var_name) {
|
["print" | "p", var_name] => match context.scope().get_value::<Dynamic>(var_name) {
|
||||||
Some(value) => println!("=> {:?}", value),
|
Some(value) => println!("=> {value:?}"),
|
||||||
None => eprintln!("Variable not found: {}", var_name),
|
None => eprintln!("Variable not found: {var_name}"),
|
||||||
},
|
},
|
||||||
["print" | "p"] => {
|
["print" | "p"] => {
|
||||||
println!("{}", context.scope().clone_visible());
|
println!("{}", context.scope().clone_visible());
|
||||||
if let Some(value) = context.this_ptr() {
|
if let Some(value) = context.this_ptr() {
|
||||||
println!("this = {:?}", value);
|
println!("this = {value:?}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
@ -379,7 +378,7 @@ fn debug_callback(
|
|||||||
.iter()
|
.iter()
|
||||||
.rev()
|
.rev()
|
||||||
{
|
{
|
||||||
println!("{}", frame)
|
println!("{frame}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
["info" | "i", "break" | "b"] => Iterator::for_each(
|
["info" | "i", "break" | "b"] => Iterator::for_each(
|
||||||
@ -396,7 +395,7 @@ fn debug_callback(
|
|||||||
print!("{}", line_num);
|
print!("{}", line_num);
|
||||||
print_source(lines, *pos, line_num.len(), (0, 0));
|
print_source(lines, *pos, line_num.len(), (0, 0));
|
||||||
}
|
}
|
||||||
_ => println!("[{}] {}", i + 1, bp),
|
_ => println!("[{}] {bp}", i + 1),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
["enable" | "en", n] => {
|
["enable" | "en", n] => {
|
||||||
@ -414,12 +413,12 @@ fn debug_callback(
|
|||||||
.get_mut(n - 1)
|
.get_mut(n - 1)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.enable(true);
|
.enable(true);
|
||||||
println!("Break-point #{} enabled.", n)
|
println!("Break-point #{n} enabled.")
|
||||||
} else {
|
} else {
|
||||||
eprintln!("\x1b[31mInvalid break-point: {}\x1b[39m", n);
|
eprintln!("\x1b[31mInvalid break-point: {n}\x1b[39m");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
eprintln!("\x1b[31mInvalid break-point: '{}'\x1b[39m", n);
|
eprintln!("\x1b[31mInvalid break-point: '{n}'\x1b[39m");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
["disable" | "dis", n] => {
|
["disable" | "dis", n] => {
|
||||||
@ -437,12 +436,12 @@ fn debug_callback(
|
|||||||
.get_mut(n - 1)
|
.get_mut(n - 1)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.enable(false);
|
.enable(false);
|
||||||
println!("Break-point #{} disabled.", n)
|
println!("Break-point #{n} disabled.")
|
||||||
} else {
|
} else {
|
||||||
eprintln!("\x1b[31mInvalid break-point: {}\x1b[39m", n);
|
eprintln!("\x1b[31mInvalid break-point: {n}\x1b[39m");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
eprintln!("\x1b[31mInvalid break-point: '{}'\x1b[39m", n);
|
eprintln!("\x1b[31mInvalid break-point: '{n}'\x1b[39m");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
["delete" | "d", n] => {
|
["delete" | "d", n] => {
|
||||||
@ -458,12 +457,12 @@ fn debug_callback(
|
|||||||
.debugger
|
.debugger
|
||||||
.break_points_mut()
|
.break_points_mut()
|
||||||
.remove(n - 1);
|
.remove(n - 1);
|
||||||
println!("Break-point #{} deleted.", n)
|
println!("Break-point #{n} deleted.")
|
||||||
} else {
|
} else {
|
||||||
eprintln!("\x1b[31mInvalid break-point: {}\x1b[39m", n);
|
eprintln!("\x1b[31mInvalid break-point: {n}\x1b[39m");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
eprintln!("\x1b[31mInvalid break-point: '{}'\x1b[39m", n);
|
eprintln!("\x1b[31mInvalid break-point: '{n}'\x1b[39m");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
["delete" | "d"] => {
|
["delete" | "d"] => {
|
||||||
@ -481,14 +480,14 @@ fn debug_callback(
|
|||||||
args,
|
args,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
};
|
};
|
||||||
println!("Break-point added for {}", bp);
|
println!("Break-point added for {bp}");
|
||||||
context
|
context
|
||||||
.global_runtime_state_mut()
|
.global_runtime_state_mut()
|
||||||
.debugger
|
.debugger
|
||||||
.break_points_mut()
|
.break_points_mut()
|
||||||
.push(bp);
|
.push(bp);
|
||||||
} else {
|
} else {
|
||||||
eprintln!("\x1b[31mInvalid number of arguments: '{}'\x1b[39m", args);
|
eprintln!("\x1b[31mInvalid number of arguments: '{args}'\x1b[39m");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Property name
|
// Property name
|
||||||
@ -498,7 +497,7 @@ fn debug_callback(
|
|||||||
name: param[1..].into(),
|
name: param[1..].into(),
|
||||||
enabled: true,
|
enabled: true,
|
||||||
};
|
};
|
||||||
println!("Break-point added for {}", bp);
|
println!("Break-point added for {bp}");
|
||||||
context
|
context
|
||||||
.global_runtime_state_mut()
|
.global_runtime_state_mut()
|
||||||
.debugger
|
.debugger
|
||||||
@ -521,14 +520,14 @@ fn debug_callback(
|
|||||||
pos: Position::new(n as u16, 0),
|
pos: Position::new(n as u16, 0),
|
||||||
enabled: true,
|
enabled: true,
|
||||||
};
|
};
|
||||||
println!("Break-point added {}", bp);
|
println!("Break-point added {bp}");
|
||||||
context
|
context
|
||||||
.global_runtime_state_mut()
|
.global_runtime_state_mut()
|
||||||
.debugger
|
.debugger
|
||||||
.break_points_mut()
|
.break_points_mut()
|
||||||
.push(bp);
|
.push(bp);
|
||||||
} else {
|
} else {
|
||||||
eprintln!("\x1b[31mInvalid line number: '{}'\x1b[39m", n);
|
eprintln!("\x1b[31mInvalid line number: '{n}'\x1b[39m");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Function name parameter
|
// Function name parameter
|
||||||
@ -537,7 +536,7 @@ fn debug_callback(
|
|||||||
name: param.trim().into(),
|
name: param.trim().into(),
|
||||||
enabled: true,
|
enabled: true,
|
||||||
};
|
};
|
||||||
println!("Break-point added for {}", bp);
|
println!("Break-point added for {bp}");
|
||||||
context
|
context
|
||||||
.global_runtime_state_mut()
|
.global_runtime_state_mut()
|
||||||
.debugger
|
.debugger
|
||||||
@ -551,7 +550,7 @@ fn debug_callback(
|
|||||||
pos,
|
pos,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
};
|
};
|
||||||
println!("Break-point added {}", bp);
|
println!("Break-point added {bp}");
|
||||||
context
|
context
|
||||||
.global_runtime_state_mut()
|
.global_runtime_state_mut()
|
||||||
.debugger
|
.debugger
|
||||||
@ -588,7 +587,7 @@ fn debug_callback(
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let title = format!("Rhai Debugger (version {})", env!("CARGO_PKG_VERSION"));
|
let title = format!("Rhai Debugger (version {})", env!("CARGO_PKG_VERSION"));
|
||||||
println!("{}", title);
|
println!("{title}");
|
||||||
println!("{0:=<1$}", "", title.len());
|
println!("{0:=<1$}", "", title.len());
|
||||||
|
|
||||||
// Initialize scripting engine
|
// Initialize scripting engine
|
||||||
|
@ -26,17 +26,16 @@ fn print_error(input: &str, mut err: EvalAltResult) {
|
|||||||
// Print error position
|
// Print error position
|
||||||
if pos.is_none() {
|
if pos.is_none() {
|
||||||
// No position
|
// No position
|
||||||
println!("{}", err);
|
println!("{err}");
|
||||||
} else {
|
} else {
|
||||||
// Specific position - print line text
|
// Specific position - print line text
|
||||||
println!("{}{}", line_no, lines[pos.line().unwrap() - 1]);
|
println!("{line_no}{}", lines[pos.line().unwrap() - 1]);
|
||||||
|
|
||||||
// Display position marker
|
// Display position marker
|
||||||
println!(
|
println!(
|
||||||
"{0:>1$} {2}",
|
"{0:>1$} {err}",
|
||||||
"^",
|
"^",
|
||||||
line_no.len() + pos.position().unwrap(),
|
line_no.len() + pos.position().unwrap(),
|
||||||
err
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -119,7 +118,7 @@ fn load_script_files(engine: &mut Engine) {
|
|||||||
for filename in env::args().skip(1) {
|
for filename in env::args().skip(1) {
|
||||||
let filename = match Path::new(&filename).canonicalize() {
|
let filename = match Path::new(&filename).canonicalize() {
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
eprintln!("Error script file path: {}\n{}", filename, err);
|
eprintln!("Error script file path: {filename}\n{err}");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
Ok(f) => {
|
Ok(f) => {
|
||||||
@ -164,7 +163,7 @@ fn load_script_files(engine: &mut Engine) {
|
|||||||
let filename = filename.to_string_lossy();
|
let filename = filename.to_string_lossy();
|
||||||
|
|
||||||
eprintln!("{:=<1$}", "", filename.len());
|
eprintln!("{:=<1$}", "", filename.len());
|
||||||
eprintln!("{}", filename);
|
eprintln!("{filename}");
|
||||||
eprintln!("{:=<1$}", "", filename.len());
|
eprintln!("{:=<1$}", "", filename.len());
|
||||||
eprintln!();
|
eprintln!();
|
||||||
|
|
||||||
@ -277,13 +276,13 @@ mod sample_functions {
|
|||||||
#[rhai_fn(name = "test")]
|
#[rhai_fn(name = "test")]
|
||||||
pub fn test2(x: &mut INT, y: INT, z: &str) {
|
pub fn test2(x: &mut INT, y: INT, z: &str) {
|
||||||
*x += y + (z.len() as INT);
|
*x += y + (z.len() as INT);
|
||||||
println!("{} {} {}", x, y, z);
|
println!("{x} {y} {z}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let title = format!("Rhai REPL tool (version {})", env!("CARGO_PKG_VERSION"));
|
let title = format!("Rhai REPL tool (version {})", env!("CARGO_PKG_VERSION"));
|
||||||
println!("{}", title);
|
println!("{title}");
|
||||||
println!("{0:=<1$}", "", title.len());
|
println!("{0:=<1$}", "", title.len());
|
||||||
|
|
||||||
#[cfg(not(feature = "no_optimize"))]
|
#[cfg(not(feature = "no_optimize"))]
|
||||||
@ -310,7 +309,13 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Register sample functions
|
// Register sample functions
|
||||||
engine.register_global_module(exported_module!(sample_functions).into());
|
engine
|
||||||
|
.register_global_module(exported_module!(sample_functions).into())
|
||||||
|
.register_get_set(
|
||||||
|
"test",
|
||||||
|
|x: &mut INT| *x % 2 == 0,
|
||||||
|
|x: &mut INT, y: bool| if y { *x *= 2 } else { *x /= 2 },
|
||||||
|
);
|
||||||
|
|
||||||
// Create scope
|
// Create scope
|
||||||
let mut scope = Scope::new();
|
let mut scope = Scope::new();
|
||||||
@ -338,11 +343,11 @@ fn main() {
|
|||||||
history_offset += 1;
|
history_offset += 1;
|
||||||
}
|
}
|
||||||
if input.contains('\n') {
|
if input.contains('\n') {
|
||||||
println!("[{}] ~~~~", replacement_index);
|
println!("[{replacement_index}] ~~~~");
|
||||||
println!("{}", input);
|
println!("{input}");
|
||||||
println!("~~~~");
|
println!("~~~~");
|
||||||
} else {
|
} else {
|
||||||
println!("[{}] {}", replacement_index, input);
|
println!("[{replacement_index}] {input}");
|
||||||
}
|
}
|
||||||
replacement_index = 0;
|
replacement_index = 0;
|
||||||
} else {
|
} else {
|
||||||
@ -374,7 +379,7 @@ fn main() {
|
|||||||
Err(ReadlineError::Interrupted) | Err(ReadlineError::Eof) => break 'main_loop,
|
Err(ReadlineError::Interrupted) | Err(ReadlineError::Eof) => break 'main_loop,
|
||||||
|
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
eprintln!("Error: {:?}", err);
|
eprintln!("Error: {err:?}");
|
||||||
break 'main_loop;
|
break 'main_loop;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -401,12 +406,12 @@ fn main() {
|
|||||||
"history" => {
|
"history" => {
|
||||||
for (i, h) in rl.history().iter().enumerate() {
|
for (i, h) in rl.history().iter().enumerate() {
|
||||||
match &h.split('\n').collect::<Vec<_>>()[..] {
|
match &h.split('\n').collect::<Vec<_>>()[..] {
|
||||||
[line] => println!("[{}] {}", history_offset + i, line),
|
[line] => println!("[{}] {line}", history_offset + i),
|
||||||
lines => {
|
lines => {
|
||||||
for (x, line) in lines.iter().enumerate() {
|
for (x, line) in lines.iter().enumerate() {
|
||||||
let number = format!("[{}]", history_offset + i);
|
let number = format!("[{}]", history_offset + i);
|
||||||
if x == 0 {
|
if x == 0 {
|
||||||
println!("{} {}", number, line.trim_end());
|
println!("{number} {}", line.trim_end());
|
||||||
} else {
|
} else {
|
||||||
println!("{0:>1$} {2}", "", number.len(), line.trim_end());
|
println!("{0:>1$} {2}", "", number.len(), line.trim_end());
|
||||||
}
|
}
|
||||||
@ -439,30 +444,30 @@ fn main() {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
"scope" => {
|
"scope" => {
|
||||||
println!("{}", scope);
|
println!("{scope}");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "no_optimize"))]
|
#[cfg(not(feature = "no_optimize"))]
|
||||||
"astu" => {
|
"astu" => {
|
||||||
// print the last un-optimized AST
|
// print the last un-optimized AST
|
||||||
println!("{:#?}\n", ast_u);
|
println!("{ast_u:#?}\n");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
"ast" => {
|
"ast" => {
|
||||||
// print the last AST
|
// print the last AST
|
||||||
println!("{:#?}\n", ast);
|
println!("{ast:#?}\n");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
#[cfg(feature = "metadata")]
|
#[cfg(feature = "metadata")]
|
||||||
"functions" => {
|
"functions" => {
|
||||||
// print a list of all registered functions
|
// print a list of all registered functions
|
||||||
for f in engine.gen_fn_signatures(false) {
|
for f in engine.gen_fn_signatures(false) {
|
||||||
println!("{}", f)
|
println!("{f}")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
for f in main_ast.iter_functions() {
|
for f in main_ast.iter_functions() {
|
||||||
println!("{}", f)
|
println!("{f}")
|
||||||
}
|
}
|
||||||
|
|
||||||
println!();
|
println!();
|
||||||
@ -505,7 +510,7 @@ fn main() {
|
|||||||
replacement = Some(line.clone());
|
replacement = Some(line.clone());
|
||||||
replacement_index = history_offset + (rl.history().len() - 1 - n);
|
replacement_index = history_offset + (rl.history().len() - 1 - n);
|
||||||
}
|
}
|
||||||
None => eprintln!("History line not found: {}", text),
|
None => eprintln!("History line not found: {text}"),
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -561,7 +566,7 @@ fn main() {
|
|||||||
engine.eval_ast_with_scope::<Dynamic>(&mut scope, &main_ast)
|
engine.eval_ast_with_scope::<Dynamic>(&mut scope, &main_ast)
|
||||||
}) {
|
}) {
|
||||||
Ok(result) if !result.is::<()>() => {
|
Ok(result) if !result.is::<()>() => {
|
||||||
println!("=> {:?}", result);
|
println!("=> {result:?}");
|
||||||
println!();
|
println!();
|
||||||
}
|
}
|
||||||
Ok(_) => (),
|
Ok(_) => (),
|
||||||
|
@ -7,12 +7,11 @@ fn eprint_error(input: &str, mut err: EvalAltResult) {
|
|||||||
let line = pos.line().unwrap();
|
let line = pos.line().unwrap();
|
||||||
let line_no = format!("{line}: ");
|
let line_no = format!("{line}: ");
|
||||||
|
|
||||||
eprintln!("{}{}", line_no, lines[line - 1]);
|
eprintln!("{line_no}{}", lines[line - 1]);
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"{:>1$} {2}",
|
"{:>1$} {err_msg}",
|
||||||
"^",
|
"^",
|
||||||
line_no.len() + pos.position().unwrap(),
|
line_no.len() + pos.position().unwrap(),
|
||||||
err_msg
|
|
||||||
);
|
);
|
||||||
eprintln!();
|
eprintln!();
|
||||||
}
|
}
|
||||||
@ -24,7 +23,7 @@ fn eprint_error(input: &str, mut err: EvalAltResult) {
|
|||||||
|
|
||||||
if pos.is_none() {
|
if pos.is_none() {
|
||||||
// No position
|
// No position
|
||||||
eprintln!("{}", err);
|
eprintln!("{err}");
|
||||||
} else {
|
} else {
|
||||||
// Specific position
|
// Specific position
|
||||||
eprint_line(&lines, pos, &err.to_string())
|
eprint_line(&lines, pos, &err.to_string())
|
||||||
@ -37,7 +36,7 @@ fn main() {
|
|||||||
for filename in env::args().skip(1) {
|
for filename in env::args().skip(1) {
|
||||||
let filename = match Path::new(&filename).canonicalize() {
|
let filename = match Path::new(&filename).canonicalize() {
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
eprintln!("Error script file path: {}\n{}", filename, err);
|
eprintln!("Error script file path: {filename}\n{err}");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
Ok(f) => match f.strip_prefix(std::env::current_dir().unwrap().canonicalize().unwrap())
|
Ok(f) => match f.strip_prefix(std::env::current_dir().unwrap().canonicalize().unwrap())
|
||||||
@ -94,7 +93,7 @@ fn main() {
|
|||||||
let filename = filename.to_string_lossy();
|
let filename = filename.to_string_lossy();
|
||||||
|
|
||||||
eprintln!("{:=<1$}", "", filename.len());
|
eprintln!("{:=<1$}", "", filename.len());
|
||||||
eprintln!("{}", filename);
|
eprintln!("{filename}");
|
||||||
eprintln!("{:=<1$}", "", filename.len());
|
eprintln!("{:=<1$}", "", filename.len());
|
||||||
eprintln!();
|
eprintln!();
|
||||||
|
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
//! Configuration settings for this Rhai build
|
//! Configuration settings for this Rhai build
|
||||||
|
//!
|
||||||
|
//! This file is auto-generated from `build.template`
|
||||||
|
|
||||||
/// Fixed hashing seeds for stable hashing.
|
/// Fixed hashing seeds for stable hashing.
|
||||||
/// Set to [`None`] to disable stable hashing.
|
/// Set to [`None`] to disable stable hashing.
|
||||||
|
112
src/engine.rs
112
src/engine.rs
@ -9,8 +9,7 @@ use crate::packages::{Package, StandardPackage};
|
|||||||
use crate::tokenizer::Token;
|
use crate::tokenizer::Token;
|
||||||
use crate::types::StringsInterner;
|
use crate::types::StringsInterner;
|
||||||
use crate::{
|
use crate::{
|
||||||
Dynamic, Identifier, ImmutableString, Locked, Module, OptimizationLevel, Position, RhaiResult,
|
Dynamic, Identifier, ImmutableString, Locked, Module, OptimizationLevel, Shared, StaticVec,
|
||||||
Shared, StaticVec,
|
|
||||||
};
|
};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
@ -86,7 +85,7 @@ pub const OP_INCLUSIVE_RANGE: &str = Token::InclusiveRange.literal_syntax();
|
|||||||
///
|
///
|
||||||
/// let result = engine.eval::<i64>("40 + 2")?;
|
/// let result = engine.eval::<i64>("40 + 2")?;
|
||||||
///
|
///
|
||||||
/// println!("Answer: {}", result); // prints 42
|
/// println!("Answer: {result}"); // prints 42
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
@ -237,18 +236,12 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "no_std"))]
|
#[cfg(not(feature = "no_std"))]
|
||||||
#[cfg(not(target_family = "wasm"))]
|
#[cfg(not(target_family = "wasm"))]
|
||||||
{
|
{
|
||||||
engine.print = Box::new(|s| println!("{}", s));
|
engine.print = Box::new(|s| println!("{s}"));
|
||||||
engine.debug = Box::new(|s, source, pos| {
|
engine.debug = Box::new(|s, source, pos| match (source, pos) {
|
||||||
source.map_or_else(
|
(Some(source), crate::Position::NONE) => println!("{source} | {s}"),
|
||||||
|| {
|
(Some(source), pos) => println!("{source} @ {pos:?} | {s}"),
|
||||||
if pos.is_none() {
|
(None, crate::Position::NONE) => println!("{s}"),
|
||||||
println!("{s}");
|
(None, pos) => println!("{pos:?} | {s}"),
|
||||||
} else {
|
|
||||||
println!("{pos:?} | {s}");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|source| println!("{source} @ {pos:?} | {s}"),
|
|
||||||
)
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -345,93 +338,4 @@ impl Engine {
|
|||||||
pub fn const_empty_string(&self) -> ImmutableString {
|
pub fn const_empty_string(&self) -> ImmutableString {
|
||||||
self.get_interned_string("")
|
self.get_interned_string("")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check a result to ensure that it is valid.
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
|
||||||
#[inline]
|
|
||||||
pub(crate) fn check_return_value(&self, result: RhaiResult, _pos: Position) -> RhaiResult {
|
|
||||||
if let Ok(ref r) = result {
|
|
||||||
self.check_data_size(r, _pos)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "unchecked")]
|
|
||||||
impl Engine {
|
|
||||||
/// The maximum levels of function calls allowed for a script.
|
|
||||||
#[inline(always)]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn max_call_levels(&self) -> usize {
|
|
||||||
usize::MAX
|
|
||||||
}
|
|
||||||
/// The maximum number of operations allowed for a script to run (0 for unlimited).
|
|
||||||
#[inline(always)]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn max_operations(&self) -> u64 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
/// The maximum number of imported [modules][crate::Module] allowed for a script.
|
|
||||||
#[inline(always)]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn max_modules(&self) -> usize {
|
|
||||||
usize::MAX
|
|
||||||
}
|
|
||||||
/// The depth limit for expressions (0 for unlimited).
|
|
||||||
#[inline(always)]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn max_expr_depth(&self) -> usize {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
/// The depth limit for expressions in functions (0 for unlimited).
|
|
||||||
#[inline(always)]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn max_function_expr_depth(&self) -> usize {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
/// The maximum length of [strings][crate::ImmutableString] (0 for unlimited).
|
|
||||||
#[inline(always)]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn max_string_size(&self) -> usize {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
/// The maximum length of [arrays][crate::Array] (0 for unlimited).
|
|
||||||
#[inline(always)]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn max_array_size(&self) -> usize {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
/// The maximum size of [object maps][crate::Map] (0 for unlimited).
|
|
||||||
#[inline(always)]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn max_map_size(&self) -> usize {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check if the number of operations stay within limit.
|
|
||||||
#[inline(always)]
|
|
||||||
pub(crate) const fn track_operation(
|
|
||||||
&self,
|
|
||||||
_: &crate::eval::GlobalRuntimeState,
|
|
||||||
_: Position,
|
|
||||||
) -> crate::RhaiResultOf<()> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check whether the size of a [`Dynamic`] is within limits.
|
|
||||||
#[inline(always)]
|
|
||||||
pub(crate) const fn check_data_size(
|
|
||||||
&self,
|
|
||||||
_: &Dynamic,
|
|
||||||
_: Position,
|
|
||||||
) -> crate::RhaiResultOf<()> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check a result to ensure that it is valid.
|
|
||||||
#[inline(always)]
|
|
||||||
pub(crate) const fn check_return_value(&self, result: RhaiResult, _: Position) -> RhaiResult {
|
|
||||||
result
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
use super::GlobalRuntimeState;
|
use super::GlobalRuntimeState;
|
||||||
use crate::types::dynamic::Union;
|
use crate::types::dynamic::Union;
|
||||||
use crate::{Dynamic, Engine, Position, RhaiResultOf, ERR};
|
use crate::{Dynamic, Engine, Position, RhaiResult, RhaiResultOf, ERR};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
|
|
||||||
@ -73,14 +73,15 @@ impl Engine {
|
|||||||
pub(crate) fn raise_err_if_over_data_size_limit(
|
pub(crate) fn raise_err_if_over_data_size_limit(
|
||||||
&self,
|
&self,
|
||||||
(_arr, _map, s): (usize, usize, usize),
|
(_arr, _map, s): (usize, usize, usize),
|
||||||
pos: Position,
|
|
||||||
) -> RhaiResultOf<()> {
|
) -> RhaiResultOf<()> {
|
||||||
if self
|
if self
|
||||||
.limits
|
.limits
|
||||||
.max_string_size
|
.max_string_size
|
||||||
.map_or(false, |max| s > max.get())
|
.map_or(false, |max| s > max.get())
|
||||||
{
|
{
|
||||||
return Err(ERR::ErrorDataTooLarge("Length of string".to_string(), pos).into());
|
return Err(
|
||||||
|
ERR::ErrorDataTooLarge("Length of string".to_string(), Position::NONE).into(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
@ -89,7 +90,9 @@ impl Engine {
|
|||||||
.max_array_size
|
.max_array_size
|
||||||
.map_or(false, |max| _arr > max.get())
|
.map_or(false, |max| _arr > max.get())
|
||||||
{
|
{
|
||||||
return Err(ERR::ErrorDataTooLarge("Size of array".to_string(), pos).into());
|
return Err(
|
||||||
|
ERR::ErrorDataTooLarge("Size of array/BLOB".to_string(), Position::NONE).into(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
@ -98,7 +101,9 @@ impl Engine {
|
|||||||
.max_map_size
|
.max_map_size
|
||||||
.map_or(false, |max| _map > max.get())
|
.map_or(false, |max| _map > max.get())
|
||||||
{
|
{
|
||||||
return Err(ERR::ErrorDataTooLarge("Size of object map".to_string(), pos).into());
|
return Err(
|
||||||
|
ERR::ErrorDataTooLarge("Size of object map".to_string(), Position::NONE).into(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -113,7 +118,8 @@ impl Engine {
|
|||||||
|
|
||||||
let sizes = Self::calc_data_sizes(value, true);
|
let sizes = Self::calc_data_sizes(value, true);
|
||||||
|
|
||||||
self.raise_err_if_over_data_size_limit(sizes, pos)
|
self.raise_err_if_over_data_size_limit(sizes)
|
||||||
|
.map_err(|err| err.fill_position(pos))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Raise an error if the size of a [`Dynamic`] is out of limits (if any).
|
/// Raise an error if the size of a [`Dynamic`] is out of limits (if any).
|
||||||
@ -150,4 +156,14 @@ impl Engine {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check a result to ensure that it is valid.
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn check_return_value(&self, result: RhaiResult, pos: Position) -> RhaiResult {
|
||||||
|
if let Ok(ref r) = result {
|
||||||
|
self.check_data_size(r, pos)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -148,35 +148,30 @@ impl fmt::Display for BreakPoint {
|
|||||||
pos,
|
pos,
|
||||||
enabled,
|
enabled,
|
||||||
} => {
|
} => {
|
||||||
if source.is_empty() {
|
if !source.is_empty() {
|
||||||
write!(f, "@ {:?}", pos)?;
|
write!(f, "{source} ")?;
|
||||||
} else {
|
|
||||||
write!(f, "{} @ {:?}", source, pos)?;
|
|
||||||
}
|
}
|
||||||
|
write!(f, "@ {pos:?}")?;
|
||||||
if !*enabled {
|
if !*enabled {
|
||||||
f.write_str(" (disabled)")?;
|
f.write_str(" (disabled)")?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Self::AtFunctionName {
|
Self::AtFunctionName { name, enabled } => {
|
||||||
name: fn_name,
|
write!(f, "{name} (...)")?;
|
||||||
enabled,
|
|
||||||
} => {
|
|
||||||
write!(f, "{} (...)", fn_name)?;
|
|
||||||
if !*enabled {
|
if !*enabled {
|
||||||
f.write_str(" (disabled)")?;
|
f.write_str(" (disabled)")?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Self::AtFunctionCall {
|
Self::AtFunctionCall {
|
||||||
name: fn_name,
|
name,
|
||||||
args,
|
args,
|
||||||
enabled,
|
enabled,
|
||||||
} => {
|
} => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"{} ({})",
|
"{name} ({})",
|
||||||
fn_name,
|
|
||||||
repeat("_").take(*args).collect::<Vec<_>>().join(", ")
|
repeat("_").take(*args).collect::<Vec<_>>().join(", ")
|
||||||
)?;
|
)?;
|
||||||
if !*enabled {
|
if !*enabled {
|
||||||
@ -185,11 +180,8 @@ impl fmt::Display for BreakPoint {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Self::AtProperty {
|
Self::AtProperty { name, enabled } => {
|
||||||
name: prop,
|
write!(f, ".{name}")?;
|
||||||
enabled,
|
|
||||||
} => {
|
|
||||||
write!(f, ".{}", prop)?;
|
|
||||||
if !*enabled {
|
if !*enabled {
|
||||||
f.write_str(" (disabled)")?;
|
f.write_str(" (disabled)")?;
|
||||||
}
|
}
|
||||||
@ -251,11 +243,10 @@ impl fmt::Display for CallStackFrame {
|
|||||||
fp.finish()?;
|
fp.finish()?;
|
||||||
|
|
||||||
if !self.pos.is_none() {
|
if !self.pos.is_none() {
|
||||||
if self.source.is_empty() {
|
if !self.source.is_empty() {
|
||||||
write!(f, " @ {:?}", self.pos)?;
|
write!(f, ": {}", self.source)?;
|
||||||
} else {
|
|
||||||
write!(f, ": {} @ {:?}", self.source, self.pos)?;
|
|
||||||
}
|
}
|
||||||
|
write!(f, " @ {:?}", self.pos)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
166
src/eval/expr.rs
166
src/eval/expr.rs
@ -188,8 +188,8 @@ impl Engine {
|
|||||||
// Find the variable in the scope
|
// Find the variable in the scope
|
||||||
let var_name = expr.get_variable_name(true).expect("`Expr::Variable`");
|
let var_name = expr.get_variable_name(true).expect("`Expr::Variable`");
|
||||||
|
|
||||||
match scope.get_index(var_name) {
|
match scope.search(var_name) {
|
||||||
Some((index, _)) => index,
|
Some(index) => index,
|
||||||
None => {
|
None => {
|
||||||
return match self.global_modules.iter().find_map(|m| m.get_var(var_name)) {
|
return match self.global_modules.iter().find_map(|m| m.get_var(var_name)) {
|
||||||
Some(val) => Ok((val.into(), var_pos)),
|
Some(val) => Ok((val.into(), var_pos)),
|
||||||
@ -251,9 +251,8 @@ impl Engine {
|
|||||||
get_builtin_binary_op_fn(operator_token.as_ref().unwrap(), operands[0], operands[1])
|
get_builtin_binary_op_fn(operator_token.as_ref().unwrap(), operands[0], operands[1])
|
||||||
{
|
{
|
||||||
// Built-in found
|
// Built-in found
|
||||||
let context = (self, name, None, &*global, lib, pos, level + 1).into();
|
let context = (self, name.as_str(), None, &*global, lib, pos, level + 1).into();
|
||||||
let result = func(context, operands);
|
return func(context, operands);
|
||||||
return self.check_return_value(result, pos);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return self
|
return self
|
||||||
@ -379,114 +378,89 @@ impl Engine {
|
|||||||
Expr::InterpolatedString(x, _) => {
|
Expr::InterpolatedString(x, _) => {
|
||||||
let mut concat = self.get_interned_string("").into();
|
let mut concat = self.get_interned_string("").into();
|
||||||
let target = &mut concat;
|
let target = &mut concat;
|
||||||
let mut result = Ok(Dynamic::UNIT);
|
|
||||||
|
|
||||||
let mut op_info = OpAssignment::new_op_assignment(OP_CONCAT, Position::NONE);
|
let mut op_info = OpAssignment::new_op_assignment(OP_CONCAT, Position::NONE);
|
||||||
let root = ("", Position::NONE);
|
let root = ("", Position::NONE);
|
||||||
|
|
||||||
for expr in &**x {
|
let result = x
|
||||||
let item =
|
.iter()
|
||||||
match self.eval_expr(scope, global, caches, lib, this_ptr, expr, level) {
|
.try_for_each(|expr| {
|
||||||
Ok(r) => r,
|
let item =
|
||||||
err => {
|
self.eval_expr(scope, global, caches, lib, this_ptr, expr, level)?;
|
||||||
result = err;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
op_info.pos = expr.start_position();
|
op_info.pos = expr.start_position();
|
||||||
|
|
||||||
if let Err(err) = self.eval_op_assignment(
|
self.eval_op_assignment(
|
||||||
global, caches, lib, &op_info, target, root, item, level,
|
global, caches, lib, &op_info, target, root, item, level,
|
||||||
) {
|
)
|
||||||
result = Err(err);
|
})
|
||||||
break;
|
.map(|_| concat.take_or_clone());
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.check_return_value(
|
self.check_return_value(result, expr.start_position())
|
||||||
result.map(|_| concat.take_or_clone()),
|
|
||||||
expr.start_position(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Expr::Array(x, ..) => {
|
Expr::Array(x, ..) => {
|
||||||
let mut array = crate::Array::with_capacity(x.len());
|
|
||||||
let mut result = Ok(Dynamic::UNIT);
|
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
let mut total_data_sizes = (0, 0, 0);
|
let mut total_data_sizes = (0, 0, 0);
|
||||||
|
|
||||||
for item_expr in &**x {
|
x.iter()
|
||||||
let value = match self
|
.try_fold(
|
||||||
.eval_expr(scope, global, caches, lib, this_ptr, item_expr, level)
|
crate::Array::with_capacity(x.len()),
|
||||||
{
|
|mut array, item_expr| {
|
||||||
Ok(r) => r.flatten(),
|
let value = self
|
||||||
err => {
|
.eval_expr(scope, global, caches, lib, this_ptr, item_expr, level)?
|
||||||
result = err;
|
.flatten();
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
if self.has_data_size_limit() {
|
if self.has_data_size_limit() {
|
||||||
let val_sizes = Self::calc_data_sizes(&value, true);
|
let val_sizes = Self::calc_data_sizes(&value, true);
|
||||||
|
|
||||||
total_data_sizes = (
|
total_data_sizes = (
|
||||||
total_data_sizes.0 + val_sizes.0,
|
total_data_sizes.0 + val_sizes.0,
|
||||||
total_data_sizes.1 + val_sizes.1,
|
total_data_sizes.1 + val_sizes.1,
|
||||||
total_data_sizes.2 + val_sizes.2,
|
total_data_sizes.2 + val_sizes.2,
|
||||||
);
|
);
|
||||||
self.raise_err_if_over_data_size_limit(
|
self.raise_err_if_over_data_size_limit(total_data_sizes)
|
||||||
total_data_sizes,
|
.map_err(|err| err.fill_position(item_expr.position()))?;
|
||||||
item_expr.position(),
|
}
|
||||||
)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
array.push(value);
|
array.push(value);
|
||||||
}
|
|
||||||
|
|
||||||
result.map(|_| array.into())
|
Ok(array)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.map(Into::into)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Expr::Map(x, ..) => {
|
Expr::Map(x, ..) => {
|
||||||
let mut map = x.1.clone();
|
|
||||||
let mut result = Ok(Dynamic::UNIT);
|
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
let mut total_data_sizes = (0, 0, 0);
|
let mut total_data_sizes = (0, 0, 0);
|
||||||
|
|
||||||
for (key, value_expr) in &x.0 {
|
x.0.iter()
|
||||||
let value = match self
|
.try_fold(x.1.clone(), |mut map, (key, value_expr)| {
|
||||||
.eval_expr(scope, global, caches, lib, this_ptr, value_expr, level)
|
let value = self
|
||||||
{
|
.eval_expr(scope, global, caches, lib, this_ptr, value_expr, level)?
|
||||||
Ok(r) => r.flatten(),
|
.flatten();
|
||||||
err => {
|
|
||||||
result = err;
|
#[cfg(not(feature = "unchecked"))]
|
||||||
break;
|
if self.has_data_size_limit() {
|
||||||
|
let delta = Self::calc_data_sizes(&value, true);
|
||||||
|
total_data_sizes = (
|
||||||
|
total_data_sizes.0 + delta.0,
|
||||||
|
total_data_sizes.1 + delta.1,
|
||||||
|
total_data_sizes.2 + delta.2,
|
||||||
|
);
|
||||||
|
self.raise_err_if_over_data_size_limit(total_data_sizes)
|
||||||
|
.map_err(|err| err.fill_position(value_expr.position()))?;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
*map.get_mut(key.as_str()).unwrap() = value;
|
||||||
if self.has_data_size_limit() {
|
|
||||||
let delta = Self::calc_data_sizes(&value, true);
|
|
||||||
total_data_sizes = (
|
|
||||||
total_data_sizes.0 + delta.0,
|
|
||||||
total_data_sizes.1 + delta.1,
|
|
||||||
total_data_sizes.2 + delta.2,
|
|
||||||
);
|
|
||||||
self.raise_err_if_over_data_size_limit(
|
|
||||||
total_data_sizes,
|
|
||||||
value_expr.position(),
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
*map.get_mut(key.as_str()).unwrap() = value;
|
Ok(map)
|
||||||
}
|
})
|
||||||
|
.map(Into::into)
|
||||||
result.map(|_| map.into())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr::And(x, ..) => {
|
Expr::And(x, ..) => {
|
||||||
@ -498,17 +472,17 @@ impl Engine {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Ok(true) = lhs {
|
match lhs {
|
||||||
self.eval_expr(scope, global, caches, lib, this_ptr, &x.rhs, level)
|
Ok(true) => self
|
||||||
|
.eval_expr(scope, global, caches, lib, this_ptr, &x.rhs, level)
|
||||||
.and_then(|v| {
|
.and_then(|v| {
|
||||||
v.as_bool()
|
v.as_bool()
|
||||||
.map_err(|typ| {
|
.map_err(|typ| {
|
||||||
self.make_type_mismatch_err::<bool>(typ, x.rhs.position())
|
self.make_type_mismatch_err::<bool>(typ, x.rhs.position())
|
||||||
})
|
})
|
||||||
.map(Into::into)
|
.map(Into::into)
|
||||||
})
|
}),
|
||||||
} else {
|
_ => lhs.map(Into::into),
|
||||||
lhs.map(Into::into)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -521,17 +495,17 @@ impl Engine {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Ok(false) = lhs {
|
match lhs {
|
||||||
self.eval_expr(scope, global, caches, lib, this_ptr, &x.rhs, level)
|
Ok(false) => self
|
||||||
|
.eval_expr(scope, global, caches, lib, this_ptr, &x.rhs, level)
|
||||||
.and_then(|v| {
|
.and_then(|v| {
|
||||||
v.as_bool()
|
v.as_bool()
|
||||||
.map_err(|typ| {
|
.map_err(|typ| {
|
||||||
self.make_type_mismatch_err::<bool>(typ, x.rhs.position())
|
self.make_type_mismatch_err::<bool>(typ, x.rhs.position())
|
||||||
})
|
})
|
||||||
.map(Into::into)
|
.map(Into::into)
|
||||||
})
|
}),
|
||||||
} else {
|
_ => lhs.map(Into::into),
|
||||||
lhs.map(Into::into)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -542,7 +516,7 @@ impl Engine {
|
|||||||
Ok(value) if value.is::<()>() => {
|
Ok(value) if value.is::<()>() => {
|
||||||
self.eval_expr(scope, global, caches, lib, this_ptr, &x.rhs, level)
|
self.eval_expr(scope, global, caches, lib, this_ptr, &x.rhs, level)
|
||||||
}
|
}
|
||||||
Ok(_) | Err(_) => lhs,
|
_ => lhs,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,9 +23,12 @@ pub type GlobalConstants =
|
|||||||
// corresponds to that key.
|
// corresponds to that key.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct GlobalRuntimeState<'a> {
|
pub struct GlobalRuntimeState<'a> {
|
||||||
|
/// Names of imported [modules][crate::Module].
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
imports: crate::StaticVec<crate::ImmutableString>,
|
||||||
/// Stack of imported [modules][crate::Module].
|
/// Stack of imported [modules][crate::Module].
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
modules: crate::StaticVec<(crate::ImmutableString, crate::Shared<crate::Module>)>,
|
modules: crate::StaticVec<crate::Shared<crate::Module>>,
|
||||||
/// Source of the current context.
|
/// Source of the current context.
|
||||||
///
|
///
|
||||||
/// No source if the string is empty.
|
/// No source if the string is empty.
|
||||||
@ -77,6 +80,8 @@ impl GlobalRuntimeState<'_> {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(engine: &Engine) -> Self {
|
pub fn new(engine: &Engine) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
imports: crate::StaticVec::new_const(),
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
modules: crate::StaticVec::new_const(),
|
modules: crate::StaticVec::new_const(),
|
||||||
source: Identifier::new_const(),
|
source: Identifier::new_const(),
|
||||||
@ -127,7 +132,7 @@ impl GlobalRuntimeState<'_> {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_shared_import(&self, index: usize) -> Option<crate::Shared<crate::Module>> {
|
pub fn get_shared_import(&self, index: usize) -> Option<crate::Shared<crate::Module>> {
|
||||||
self.modules.get(index).map(|(_, m)| m).cloned()
|
self.modules.get(index).cloned()
|
||||||
}
|
}
|
||||||
/// Get a mutable reference to the globally-imported [module][crate::Module] at a
|
/// Get a mutable reference to the globally-imported [module][crate::Module] at a
|
||||||
/// particular index.
|
/// particular index.
|
||||||
@ -141,7 +146,7 @@ impl GlobalRuntimeState<'_> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
index: usize,
|
index: usize,
|
||||||
) -> Option<&mut crate::Shared<crate::Module>> {
|
) -> Option<&mut crate::Shared<crate::Module>> {
|
||||||
self.modules.get_mut(index).map(|(_, m)| m)
|
self.modules.get_mut(index)
|
||||||
}
|
}
|
||||||
/// Get the index of a globally-imported [module][crate::Module] by name.
|
/// Get the index of a globally-imported [module][crate::Module] by name.
|
||||||
///
|
///
|
||||||
@ -150,13 +155,11 @@ impl GlobalRuntimeState<'_> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn find_import(&self, name: &str) -> Option<usize> {
|
pub fn find_import(&self, name: &str) -> Option<usize> {
|
||||||
let len = self.modules.len();
|
self.imports
|
||||||
|
|
||||||
self.modules
|
|
||||||
.iter()
|
.iter()
|
||||||
.rev()
|
.rev()
|
||||||
.position(|(key, _)| key.as_str() == name)
|
.position(|key| key.as_str() == name)
|
||||||
.map(|i| len - 1 - i)
|
.map(|i| self.imports.len() - 1 - i)
|
||||||
}
|
}
|
||||||
/// Push an imported [module][crate::Module] onto the stack.
|
/// Push an imported [module][crate::Module] onto the stack.
|
||||||
///
|
///
|
||||||
@ -168,7 +171,8 @@ impl GlobalRuntimeState<'_> {
|
|||||||
name: impl Into<crate::ImmutableString>,
|
name: impl Into<crate::ImmutableString>,
|
||||||
module: impl Into<crate::Shared<crate::Module>>,
|
module: impl Into<crate::Shared<crate::Module>>,
|
||||||
) {
|
) {
|
||||||
self.modules.push((name.into(), module.into()));
|
self.imports.push(name.into());
|
||||||
|
self.modules.push(module.into());
|
||||||
}
|
}
|
||||||
/// Truncate the stack of globally-imported [modules][crate::Module] to a particular length.
|
/// Truncate the stack of globally-imported [modules][crate::Module] to a particular length.
|
||||||
///
|
///
|
||||||
@ -176,17 +180,18 @@ impl GlobalRuntimeState<'_> {
|
|||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn truncate_imports(&mut self, size: usize) {
|
pub fn truncate_imports(&mut self, size: usize) {
|
||||||
|
self.imports.truncate(size);
|
||||||
self.modules.truncate(size);
|
self.modules.truncate(size);
|
||||||
}
|
}
|
||||||
/// Get an iterator to the stack of globally-imported [modules][crate::Module] in reverse order.
|
/// Get an iterator to the stack of globally-imported [modules][crate::Module] in reverse order.
|
||||||
///
|
///
|
||||||
/// Not available under `no_module`.
|
/// Not available under `no_module`.
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
#[allow(dead_code)]
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn iter_imports(&self) -> impl Iterator<Item = (&str, &crate::Module)> {
|
pub fn iter_imports(&self) -> impl Iterator<Item = (&str, &crate::Module)> {
|
||||||
self.modules
|
self.imports
|
||||||
.iter()
|
.iter()
|
||||||
|
.zip(self.modules.iter())
|
||||||
.rev()
|
.rev()
|
||||||
.map(|(name, module)| (name.as_str(), &**module))
|
.map(|(name, module)| (name.as_str(), &**module))
|
||||||
}
|
}
|
||||||
@ -194,23 +199,32 @@ impl GlobalRuntimeState<'_> {
|
|||||||
///
|
///
|
||||||
/// Not available under `no_module`.
|
/// Not available under `no_module`.
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
#[allow(dead_code)]
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn iter_imports_raw(
|
pub(crate) fn iter_imports_raw(
|
||||||
&self,
|
&self,
|
||||||
) -> impl Iterator<Item = &(crate::ImmutableString, crate::Shared<crate::Module>)> {
|
) -> impl Iterator<Item = (&crate::ImmutableString, &crate::Shared<crate::Module>)> {
|
||||||
self.modules.iter().rev()
|
self.imports.iter().zip(self.modules.iter()).rev()
|
||||||
}
|
}
|
||||||
/// Get an iterator to the stack of globally-imported [modules][crate::Module] in forward order.
|
/// Get an iterator to the stack of globally-imported [modules][crate::Module] in forward order.
|
||||||
///
|
///
|
||||||
/// Not available under `no_module`.
|
/// Not available under `no_module`.
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
#[allow(dead_code)]
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn scan_imports_raw(
|
pub fn scan_imports_raw(
|
||||||
&self,
|
&self,
|
||||||
) -> impl Iterator<Item = &(crate::ImmutableString, crate::Shared<crate::Module>)> {
|
) -> impl Iterator<Item = (&crate::ImmutableString, &crate::Shared<crate::Module>)> {
|
||||||
self.modules.iter()
|
self.imports.iter().zip(self.modules.iter())
|
||||||
|
}
|
||||||
|
/// Can the particular function with [`Dynamic`] parameter(s) exist in the stack of
|
||||||
|
/// globally-imported [modules][crate::Module]?
|
||||||
|
///
|
||||||
|
/// Not available under `no_module`.
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn may_contain_dynamic_fn(&self, hash_script: u64) -> bool {
|
||||||
|
self.modules
|
||||||
|
.iter()
|
||||||
|
.any(|m| m.may_contain_dynamic_fn(hash_script))
|
||||||
}
|
}
|
||||||
/// Does the specified function hash key exist in the stack of globally-imported
|
/// Does the specified function hash key exist in the stack of globally-imported
|
||||||
/// [modules][crate::Module]?
|
/// [modules][crate::Module]?
|
||||||
@ -221,9 +235,7 @@ impl GlobalRuntimeState<'_> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn contains_qualified_fn(&self, hash: u64) -> bool {
|
pub fn contains_qualified_fn(&self, hash: u64) -> bool {
|
||||||
self.modules
|
self.modules.iter().any(|m| m.contains_qualified_fn(hash))
|
||||||
.iter()
|
|
||||||
.any(|(_, m)| m.contains_qualified_fn(hash))
|
|
||||||
}
|
}
|
||||||
/// Get the specified function via its hash key from the stack of globally-imported
|
/// Get the specified function via its hash key from the stack of globally-imported
|
||||||
/// [modules][crate::Module].
|
/// [modules][crate::Module].
|
||||||
@ -239,7 +251,7 @@ impl GlobalRuntimeState<'_> {
|
|||||||
self.modules
|
self.modules
|
||||||
.iter()
|
.iter()
|
||||||
.rev()
|
.rev()
|
||||||
.find_map(|(_, m)| m.get_qualified_fn(hash).map(|f| (f, m.id())))
|
.find_map(|m| m.get_qualified_fn(hash).map(|f| (f, m.id())))
|
||||||
}
|
}
|
||||||
/// Does the specified [`TypeId`][std::any::TypeId] iterator exist in the stack of
|
/// Does the specified [`TypeId`][std::any::TypeId] iterator exist in the stack of
|
||||||
/// globally-imported [modules][crate::Module]?
|
/// globally-imported [modules][crate::Module]?
|
||||||
@ -250,9 +262,7 @@ impl GlobalRuntimeState<'_> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn contains_iter(&self, id: std::any::TypeId) -> bool {
|
pub fn contains_iter(&self, id: std::any::TypeId) -> bool {
|
||||||
self.modules
|
self.modules.iter().any(|m| m.contains_qualified_iter(id))
|
||||||
.iter()
|
|
||||||
.any(|(_, m)| m.contains_qualified_iter(id))
|
|
||||||
}
|
}
|
||||||
/// Get the specified [`TypeId`][std::any::TypeId] iterator from the stack of globally-imported
|
/// Get the specified [`TypeId`][std::any::TypeId] iterator from the stack of globally-imported
|
||||||
/// [modules][crate::Module].
|
/// [modules][crate::Module].
|
||||||
@ -265,7 +275,7 @@ impl GlobalRuntimeState<'_> {
|
|||||||
self.modules
|
self.modules
|
||||||
.iter()
|
.iter()
|
||||||
.rev()
|
.rev()
|
||||||
.find_map(|(_, m)| m.get_qualified_iter(id))
|
.find_map(|m| m.get_qualified_iter(id))
|
||||||
}
|
}
|
||||||
/// Get the current source.
|
/// Get the current source.
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -309,25 +319,29 @@ impl GlobalRuntimeState<'_> {
|
|||||||
impl IntoIterator for GlobalRuntimeState<'_> {
|
impl IntoIterator for GlobalRuntimeState<'_> {
|
||||||
type Item = (crate::ImmutableString, crate::Shared<crate::Module>);
|
type Item = (crate::ImmutableString, crate::Shared<crate::Module>);
|
||||||
type IntoIter = std::iter::Rev<
|
type IntoIter = std::iter::Rev<
|
||||||
smallvec::IntoIter<
|
std::iter::Zip<
|
||||||
[(crate::ImmutableString, crate::Shared<crate::Module>); crate::STATIC_VEC_INLINE_SIZE],
|
smallvec::IntoIter<[crate::ImmutableString; crate::STATIC_VEC_INLINE_SIZE]>,
|
||||||
|
smallvec::IntoIter<[crate::Shared<crate::Module>; crate::STATIC_VEC_INLINE_SIZE]>,
|
||||||
>,
|
>,
|
||||||
>;
|
>;
|
||||||
|
|
||||||
fn into_iter(self) -> Self::IntoIter {
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
self.modules.into_iter().rev()
|
self.imports.into_iter().zip(self.modules.into_iter()).rev()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
impl<'a> IntoIterator for &'a GlobalRuntimeState<'_> {
|
impl<'a> IntoIterator for &'a GlobalRuntimeState<'_> {
|
||||||
type Item = &'a (crate::ImmutableString, crate::Shared<crate::Module>);
|
type Item = (&'a crate::ImmutableString, &'a crate::Shared<crate::Module>);
|
||||||
type IntoIter = std::iter::Rev<
|
type IntoIter = std::iter::Rev<
|
||||||
std::slice::Iter<'a, (crate::ImmutableString, crate::Shared<crate::Module>)>,
|
std::iter::Zip<
|
||||||
|
std::slice::Iter<'a, crate::ImmutableString>,
|
||||||
|
std::slice::Iter<'a, crate::Shared<crate::Module>>,
|
||||||
|
>,
|
||||||
>;
|
>;
|
||||||
|
|
||||||
fn into_iter(self) -> Self::IntoIter {
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
self.modules.iter().rev()
|
self.imports.iter().zip(self.modules.iter()).rev()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -338,7 +352,8 @@ impl<K: Into<crate::ImmutableString>, M: Into<crate::Shared<crate::Module>>> Ext
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn extend<T: IntoIterator<Item = (K, M)>>(&mut self, iter: T) {
|
fn extend<T: IntoIterator<Item = (K, M)>>(&mut self, iter: T) {
|
||||||
for (k, m) in iter {
|
for (k, m) in iter {
|
||||||
self.modules.push((k.into(), m.into()));
|
self.imports.push(k.into());
|
||||||
|
self.modules.push(m.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -350,7 +365,7 @@ impl fmt::Debug for GlobalRuntimeState<'_> {
|
|||||||
let mut f = f.debug_struct("GlobalRuntimeState");
|
let mut f = f.debug_struct("GlobalRuntimeState");
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
f.field("imports", &self.modules);
|
f.field("imports", &self.scan_imports_raw().collect::<Vec<_>>());
|
||||||
|
|
||||||
f.field("source", &self.source)
|
f.field("source", &self.source)
|
||||||
.field("num_operations", &self.num_operations);
|
.field("num_operations", &self.num_operations);
|
||||||
|
@ -22,3 +22,36 @@ pub use eval_context::EvalContext;
|
|||||||
pub use global_state::GlobalConstants;
|
pub use global_state::GlobalConstants;
|
||||||
pub use global_state::GlobalRuntimeState;
|
pub use global_state::GlobalRuntimeState;
|
||||||
pub use target::{calc_index, calc_offset_len, Target};
|
pub use target::{calc_index, calc_offset_len, Target};
|
||||||
|
|
||||||
|
#[cfg(feature = "unchecked")]
|
||||||
|
mod unchecked {
|
||||||
|
use crate::{eval::GlobalRuntimeState, Dynamic, Engine, Position, RhaiResult, RhaiResultOf};
|
||||||
|
|
||||||
|
impl Engine {
|
||||||
|
/// Check if the number of operations stay within limit.
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) const fn track_operation(
|
||||||
|
&self,
|
||||||
|
_: &GlobalRuntimeState,
|
||||||
|
_: Position,
|
||||||
|
) -> RhaiResultOf<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check whether the size of a [`Dynamic`] is within limits.
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) const fn check_data_size(&self, _: &Dynamic, _: Position) -> RhaiResultOf<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check a result to ensure that it is valid.
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) const fn check_return_value(
|
||||||
|
&self,
|
||||||
|
result: RhaiResult,
|
||||||
|
_: Position,
|
||||||
|
) -> RhaiResult {
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
305
src/eval/stmt.rs
305
src/eval/stmt.rs
@ -48,13 +48,11 @@ impl Engine {
|
|||||||
global.scope_level += 1;
|
global.scope_level += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut result = Ok(Dynamic::UNIT);
|
let result = statements.iter().try_fold(Dynamic::UNIT, |_, stmt| {
|
||||||
|
|
||||||
for stmt in statements {
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
let imports_len = global.num_imports();
|
let imports_len = global.num_imports();
|
||||||
|
|
||||||
result = self.eval_stmt(
|
let result = self.eval_stmt(
|
||||||
scope,
|
scope,
|
||||||
global,
|
global,
|
||||||
caches,
|
caches,
|
||||||
@ -63,11 +61,7 @@ impl Engine {
|
|||||||
stmt,
|
stmt,
|
||||||
restore_orig_state,
|
restore_orig_state,
|
||||||
level,
|
level,
|
||||||
);
|
)?;
|
||||||
|
|
||||||
if result.is_err() {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
if matches!(stmt, Stmt::Import(..)) {
|
if matches!(stmt, Stmt::Import(..)) {
|
||||||
@ -92,7 +86,9 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
Ok(result)
|
||||||
|
});
|
||||||
|
|
||||||
// If imports list is modified, pop the functions lookup cache
|
// If imports list is modified, pop the functions lookup cache
|
||||||
caches.rewind_fn_resolution_caches(orig_fn_resolution_caches_len);
|
caches.rewind_fn_resolution_caches(orig_fn_resolution_caches_len);
|
||||||
@ -150,11 +146,7 @@ impl Engine {
|
|||||||
// Built-in found
|
// Built-in found
|
||||||
let op = op_assign.literal_syntax();
|
let op = op_assign.literal_syntax();
|
||||||
let context = (self, op, None, &*global, lib, *op_pos, level).into();
|
let context = (self, op, None, &*global, lib, *op_pos, level).into();
|
||||||
let result = func(context, args).map(|_| ());
|
return func(context, args).map(|_| ());
|
||||||
|
|
||||||
self.check_data_size(args[0], root.1)?;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,7 +156,7 @@ impl Engine {
|
|||||||
match self.call_native_fn(
|
match self.call_native_fn(
|
||||||
global, caches, lib, op_assign, hash, args, true, true, *op_pos, level,
|
global, caches, lib, op_assign, hash, args, true, true, *op_pos, level,
|
||||||
) {
|
) {
|
||||||
Ok(_) => self.check_data_size(args[0], root.1)?,
|
Ok(_) => (),
|
||||||
Err(err) if matches!(*err, ERR::ErrorFunctionNotFound(ref f, ..) if f.starts_with(op_assign)) =>
|
Err(err) if matches!(*err, ERR::ErrorFunctionNotFound(ref f, ..) if f.starts_with(op_assign)) =>
|
||||||
{
|
{
|
||||||
// Expand to `var = var op rhs`
|
// Expand to `var = var op rhs`
|
||||||
@ -178,6 +170,8 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
Err(err) => return Err(err),
|
Err(err) => return Err(err),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.check_data_size(args[0], root.1)?;
|
||||||
} else {
|
} else {
|
||||||
// Normal assignment
|
// Normal assignment
|
||||||
*target.write_lock::<Dynamic>().unwrap() = new_val;
|
*target.write_lock::<Dynamic>().unwrap() = new_val;
|
||||||
@ -362,24 +356,14 @@ impl Engine {
|
|||||||
});
|
});
|
||||||
|
|
||||||
match guard_val {
|
match guard_val {
|
||||||
Ok(true) => {
|
Ok(true) if if_block.is_empty() => Ok(Dynamic::UNIT),
|
||||||
if if_block.is_empty() {
|
Ok(true) => self.eval_stmt_block(
|
||||||
Ok(Dynamic::UNIT)
|
scope, global, caches, lib, this_ptr, if_block, true, level,
|
||||||
} else {
|
),
|
||||||
self.eval_stmt_block(
|
Ok(false) if else_block.is_empty() => Ok(Dynamic::UNIT),
|
||||||
scope, global, caches, lib, this_ptr, if_block, true, level,
|
Ok(false) => self.eval_stmt_block(
|
||||||
)
|
scope, global, caches, lib, this_ptr, else_block, true, level,
|
||||||
}
|
),
|
||||||
}
|
|
||||||
Ok(false) => {
|
|
||||||
if else_block.is_empty() {
|
|
||||||
Ok(Dynamic::UNIT)
|
|
||||||
} else {
|
|
||||||
self.eval_stmt_block(
|
|
||||||
scope, global, caches, lib, this_ptr, else_block, true, level,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
err => err.map(Into::into),
|
err => err.map(Into::into),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -429,16 +413,11 @@ impl Engine {
|
|||||||
};
|
};
|
||||||
|
|
||||||
match cond_result {
|
match cond_result {
|
||||||
Ok(true) => {
|
Ok(true) => result = Ok(Some(&block.expr)),
|
||||||
result = Ok(Some(&block.expr));
|
Ok(false) => continue,
|
||||||
break;
|
_ => result = cond_result.map(|_| None),
|
||||||
}
|
|
||||||
Ok(false) => (),
|
|
||||||
_ => {
|
|
||||||
result = cond_result.map(|_| None);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
result
|
result
|
||||||
@ -469,7 +448,6 @@ impl Engine {
|
|||||||
Ok(false) => continue,
|
Ok(false) => continue,
|
||||||
_ => result = cond_result.map(|_| None),
|
_ => result = cond_result.map(|_| None),
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -500,41 +478,15 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Loop
|
// Loop
|
||||||
Stmt::While(x, ..) if matches!(x.0, Expr::Unit(..)) => loop {
|
Stmt::While(x, ..) if matches!(x.0, Expr::Unit(..) | Expr::BoolConstant(true, ..)) => {
|
||||||
let (.., body) = &**x;
|
let (.., body) = &**x;
|
||||||
|
|
||||||
if body.is_empty() {
|
if body.is_empty() {
|
||||||
self.track_operation(global, body.position())?;
|
loop {
|
||||||
} else {
|
self.track_operation(global, body.position())?;
|
||||||
match self
|
|
||||||
.eval_stmt_block(scope, global, caches, lib, this_ptr, body, true, level)
|
|
||||||
{
|
|
||||||
Ok(_) => (),
|
|
||||||
Err(err) => match *err {
|
|
||||||
ERR::LoopBreak(false, ..) => (),
|
|
||||||
ERR::LoopBreak(true, ..) => break Ok(Dynamic::UNIT),
|
|
||||||
_ => break Err(err),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
},
|
loop {
|
||||||
|
|
||||||
// While loop
|
|
||||||
Stmt::While(x, ..) => loop {
|
|
||||||
let (expr, body) = &**x;
|
|
||||||
|
|
||||||
let condition = self
|
|
||||||
.eval_expr(scope, global, caches, lib, this_ptr, expr, level)
|
|
||||||
.and_then(|v| {
|
|
||||||
v.as_bool().map_err(|typ| {
|
|
||||||
self.make_type_mismatch_err::<bool>(typ, expr.position())
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
match condition {
|
|
||||||
Ok(false) => break Ok(Dynamic::UNIT),
|
|
||||||
Ok(true) if body.is_empty() => (),
|
|
||||||
Ok(true) => {
|
|
||||||
match self.eval_stmt_block(
|
match self.eval_stmt_block(
|
||||||
scope, global, caches, lib, this_ptr, body, true, level,
|
scope, global, caches, lib, this_ptr, body, true, level,
|
||||||
) {
|
) {
|
||||||
@ -546,42 +498,76 @@ impl Engine {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err => break err.map(|_| Dynamic::UNIT),
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
|
// While loop
|
||||||
|
Stmt::While(x, ..) => {
|
||||||
|
let (expr, body) = &**x;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let condition = self
|
||||||
|
.eval_expr(scope, global, caches, lib, this_ptr, expr, level)
|
||||||
|
.and_then(|v| {
|
||||||
|
v.as_bool().map_err(|typ| {
|
||||||
|
self.make_type_mismatch_err::<bool>(typ, expr.position())
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
match condition {
|
||||||
|
Ok(false) => break Ok(Dynamic::UNIT),
|
||||||
|
Ok(true) if body.is_empty() => (),
|
||||||
|
Ok(true) => {
|
||||||
|
match self.eval_stmt_block(
|
||||||
|
scope, global, caches, lib, this_ptr, body, true, level,
|
||||||
|
) {
|
||||||
|
Ok(_) => (),
|
||||||
|
Err(err) => match *err {
|
||||||
|
ERR::LoopBreak(false, ..) => (),
|
||||||
|
ERR::LoopBreak(true, ..) => break Ok(Dynamic::UNIT),
|
||||||
|
_ => break Err(err),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err => break err.map(|_| Dynamic::UNIT),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Do loop
|
// Do loop
|
||||||
Stmt::Do(x, options, ..) => loop {
|
Stmt::Do(x, options, ..) => {
|
||||||
let (expr, body) = &**x;
|
let (expr, body) = &**x;
|
||||||
let is_while = !options.contains(ASTFlags::NEGATED);
|
let is_while = !options.contains(ASTFlags::NEGATED);
|
||||||
|
|
||||||
if !body.is_empty() {
|
loop {
|
||||||
match self
|
if !body.is_empty() {
|
||||||
.eval_stmt_block(scope, global, caches, lib, this_ptr, body, true, level)
|
match self.eval_stmt_block(
|
||||||
{
|
scope, global, caches, lib, this_ptr, body, true, level,
|
||||||
|
) {
|
||||||
|
Ok(_) => (),
|
||||||
|
Err(err) => match *err {
|
||||||
|
ERR::LoopBreak(false, ..) => continue,
|
||||||
|
ERR::LoopBreak(true, ..) => break Ok(Dynamic::UNIT),
|
||||||
|
_ => break Err(err),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let condition = self
|
||||||
|
.eval_expr(scope, global, caches, lib, this_ptr, expr, level)
|
||||||
|
.and_then(|v| {
|
||||||
|
v.as_bool().map_err(|typ| {
|
||||||
|
self.make_type_mismatch_err::<bool>(typ, expr.position())
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
match condition {
|
||||||
|
Ok(condition) if condition ^ is_while => break Ok(Dynamic::UNIT),
|
||||||
Ok(_) => (),
|
Ok(_) => (),
|
||||||
Err(err) => match *err {
|
err => break err.map(|_| Dynamic::UNIT),
|
||||||
ERR::LoopBreak(false, ..) => continue,
|
|
||||||
ERR::LoopBreak(true, ..) => break Ok(Dynamic::UNIT),
|
|
||||||
_ => break Err(err),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
let condition = self
|
|
||||||
.eval_expr(scope, global, caches, lib, this_ptr, expr, level)
|
|
||||||
.and_then(|v| {
|
|
||||||
v.as_bool().map_err(|typ| {
|
|
||||||
self.make_type_mismatch_err::<bool>(typ, expr.position())
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
match condition {
|
|
||||||
Ok(condition) if condition ^ is_while => break Ok(Dynamic::UNIT),
|
|
||||||
Ok(_) => (),
|
|
||||||
err => break err.map(|_| Dynamic::UNIT),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// For loop
|
// For loop
|
||||||
Stmt::For(x, ..) => {
|
Stmt::For(x, ..) => {
|
||||||
@ -626,68 +612,58 @@ impl Engine {
|
|||||||
scope.push(var_name.name.clone(), ());
|
scope.push(var_name.name.clone(), ());
|
||||||
let index = scope.len() - 1;
|
let index = scope.len() - 1;
|
||||||
|
|
||||||
let mut loop_result = Ok(Dynamic::UNIT);
|
let loop_result = func(iter_obj)
|
||||||
|
.enumerate()
|
||||||
|
.try_for_each(|(x, iter_value)| {
|
||||||
|
// Increment counter
|
||||||
|
if counter_index < usize::MAX {
|
||||||
|
// As the variable increments from 0, this should always work
|
||||||
|
// since any overflow will first be caught below.
|
||||||
|
let index_value = x as INT;
|
||||||
|
|
||||||
for (x, iter_value) in func(iter_obj).enumerate() {
|
#[cfg(not(feature = "unchecked"))]
|
||||||
// Increment counter
|
if index_value > crate::MAX_USIZE_INT {
|
||||||
if counter_index < usize::MAX {
|
return Err(ERR::ErrorArithmetic(
|
||||||
// As the variable increments from 0, this should always work
|
format!("for-loop counter overflow: {x}"),
|
||||||
// since any overflow will first be caught below.
|
counter.pos,
|
||||||
let index_value = x as INT;
|
)
|
||||||
|
.into());
|
||||||
#[cfg(not(feature = "unchecked"))]
|
|
||||||
if index_value > crate::MAX_USIZE_INT {
|
|
||||||
loop_result = Err(ERR::ErrorArithmetic(
|
|
||||||
format!("for-loop counter overflow: {x}"),
|
|
||||||
counter.pos,
|
|
||||||
)
|
|
||||||
.into());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
*scope.get_mut_by_index(counter_index).write_lock().unwrap() =
|
|
||||||
Dynamic::from_int(index_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
let value = match iter_value {
|
|
||||||
Ok(v) => v.flatten(),
|
|
||||||
Err(err) => {
|
|
||||||
loop_result = Err(err.fill_position(expr.position()));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
*scope.get_mut_by_index(index).write_lock().unwrap() = value;
|
|
||||||
|
|
||||||
if let Err(err) = self.track_operation(global, statements.position()) {
|
|
||||||
loop_result = Err(err);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if statements.is_empty() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let result = self.eval_stmt_block(
|
|
||||||
scope, global, caches, lib, this_ptr, statements, true, level,
|
|
||||||
);
|
|
||||||
|
|
||||||
match result {
|
|
||||||
Ok(_) => (),
|
|
||||||
Err(err) => match *err {
|
|
||||||
ERR::LoopBreak(false, ..) => (),
|
|
||||||
ERR::LoopBreak(true, ..) => break,
|
|
||||||
_ => {
|
|
||||||
loop_result = Err(err);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
}
|
*scope.get_mut_by_index(counter_index).write_lock().unwrap() =
|
||||||
}
|
Dynamic::from_int(index_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
let value = match iter_value {
|
||||||
|
Ok(v) => v.flatten(),
|
||||||
|
Err(err) => return Err(err.fill_position(expr.position())),
|
||||||
|
};
|
||||||
|
|
||||||
|
*scope.get_mut_by_index(index).write_lock().unwrap() = value;
|
||||||
|
|
||||||
|
self.track_operation(global, statements.position())?;
|
||||||
|
|
||||||
|
if statements.is_empty() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
self.eval_stmt_block(
|
||||||
|
scope, global, caches, lib, this_ptr, statements, true, level,
|
||||||
|
)
|
||||||
|
.map(|_| ())
|
||||||
|
.or_else(|err| match *err {
|
||||||
|
ERR::LoopBreak(false, ..) => Ok(()),
|
||||||
|
_ => Err(err),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.or_else(|err| match *err {
|
||||||
|
ERR::LoopBreak(true, ..) => Ok(()),
|
||||||
|
_ => Err(err),
|
||||||
|
});
|
||||||
|
|
||||||
scope.rewind(orig_scope_len);
|
scope.rewind(orig_scope_len);
|
||||||
|
|
||||||
loop_result
|
loop_result.map(|_| Dynamic::UNIT)
|
||||||
} else {
|
} else {
|
||||||
Err(ERR::ErrorFor(expr.start_position()).into())
|
Err(ERR::ErrorFor(expr.start_position()).into())
|
||||||
}
|
}
|
||||||
@ -983,7 +959,7 @@ impl Engine {
|
|||||||
Stmt::Export(x, ..) => {
|
Stmt::Export(x, ..) => {
|
||||||
let (Ident { name, pos, .. }, Ident { name: alias, .. }) = &**x;
|
let (Ident { name, pos, .. }, Ident { name: alias, .. }) = &**x;
|
||||||
// Mark scope variables as public
|
// Mark scope variables as public
|
||||||
if let Some((index, ..)) = scope.get_index(name) {
|
if let Some(index) = scope.search(name) {
|
||||||
let alias = if alias.is_empty() { name } else { alias }.clone();
|
let alias = if alias.is_empty() { name } else { alias }.clone();
|
||||||
scope.add_alias_by_index(index, alias.into());
|
scope.add_alias_by_index(index, alias.into());
|
||||||
Ok(Dynamic::UNIT)
|
Ok(Dynamic::UNIT)
|
||||||
@ -994,8 +970,13 @@ impl Engine {
|
|||||||
|
|
||||||
// Share statement
|
// Share statement
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
Stmt::Share(name, pos) => {
|
Stmt::Share(x, pos) => {
|
||||||
if let Some((index, ..)) = scope.get_index(name) {
|
let (name, index) = &**x;
|
||||||
|
|
||||||
|
if let Some(index) = index
|
||||||
|
.map(|n| scope.len() - n.get())
|
||||||
|
.or_else(|| scope.search(name))
|
||||||
|
{
|
||||||
let val = scope.get_mut_by_index(index);
|
let val = scope.get_mut_by_index(index);
|
||||||
|
|
||||||
if !val.is_shared() {
|
if !val.is_shared() {
|
||||||
|
@ -2,9 +2,12 @@
|
|||||||
|
|
||||||
use crate::types::dynamic::Variant;
|
use crate::types::dynamic::Variant;
|
||||||
use crate::{Dynamic, Position, RhaiResultOf};
|
use crate::{Dynamic, Position, RhaiResultOf};
|
||||||
use std::ops::{Deref, DerefMut};
|
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
|
use std::{
|
||||||
|
borrow::Borrow,
|
||||||
|
ops::{Deref, DerefMut},
|
||||||
|
};
|
||||||
|
|
||||||
// Calculate an offset+len pair given an actual length of the underlying array.
|
// Calculate an offset+len pair given an actual length of the underlying array.
|
||||||
//
|
//
|
||||||
@ -422,6 +425,14 @@ impl AsRef<Dynamic> for Target<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Borrow<Dynamic> for Target<'_> {
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
fn borrow(&self) -> &Dynamic {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl DerefMut for Target<'_> {
|
impl DerefMut for Target<'_> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn deref_mut(&mut self) -> &mut Dynamic {
|
fn deref_mut(&mut self) -> &mut Dynamic {
|
||||||
|
@ -2,8 +2,10 @@
|
|||||||
|
|
||||||
use super::call::FnCallArgs;
|
use super::call::FnCallArgs;
|
||||||
use super::native::FnBuiltin;
|
use super::native::FnBuiltin;
|
||||||
use crate::tokenizer::Token;
|
use crate::tokenizer::{Token, Token::*};
|
||||||
use crate::{Dynamic, ExclusiveRange, ImmutableString, InclusiveRange, INT};
|
use crate::{
|
||||||
|
Dynamic, ExclusiveRange, ImmutableString, InclusiveRange, NativeCallContext, RhaiResult, INT,
|
||||||
|
};
|
||||||
use std::any::TypeId;
|
use std::any::TypeId;
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
@ -63,6 +65,19 @@ fn is_numeric(type_id: TypeId) -> bool {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A function that returns `true`.
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
fn const_true_fn(_: NativeCallContext, _: &mut [&mut Dynamic]) -> RhaiResult {
|
||||||
|
Ok(Dynamic::TRUE)
|
||||||
|
}
|
||||||
|
/// A function that returns `false`.
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
fn const_false_fn(_: NativeCallContext, _: &mut [&mut Dynamic]) -> RhaiResult {
|
||||||
|
Ok(Dynamic::FALSE)
|
||||||
|
}
|
||||||
|
|
||||||
/// Build in common binary operator implementations to avoid the cost of calling a registered function.
|
/// Build in common binary operator implementations to avoid the cost of calling a registered function.
|
||||||
///
|
///
|
||||||
/// The return function will be registered as a _method_, so the first parameter cannot be consumed.
|
/// The return function will be registered as a _method_, so the first parameter cannot be consumed.
|
||||||
@ -131,46 +146,46 @@ pub fn get_builtin_binary_op_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Option<
|
|||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
match op {
|
match op {
|
||||||
Token::Plus => return Some(impl_op!(INT => add(as_int, as_int))),
|
Plus => return Some(impl_op!(INT => add(as_int, as_int))),
|
||||||
Token::Minus => return Some(impl_op!(INT => subtract(as_int, as_int))),
|
Minus => return Some(impl_op!(INT => subtract(as_int, as_int))),
|
||||||
Token::Multiply => return Some(impl_op!(INT => multiply(as_int, as_int))),
|
Multiply => return Some(impl_op!(INT => multiply(as_int, as_int))),
|
||||||
Token::Divide => return Some(impl_op!(INT => divide(as_int, as_int))),
|
Divide => return Some(impl_op!(INT => divide(as_int, as_int))),
|
||||||
Token::Modulo => return Some(impl_op!(INT => modulo(as_int, as_int))),
|
Modulo => return Some(impl_op!(INT => modulo(as_int, as_int))),
|
||||||
Token::PowerOf => return Some(impl_op!(INT => power(as_int, as_int))),
|
PowerOf => return Some(impl_op!(INT => power(as_int, as_int))),
|
||||||
Token::RightShift => return Some(impl_op!(INT => shift_right(as_int, as_int))),
|
RightShift => return Some(impl_op!(INT => shift_right(as_int, as_int))),
|
||||||
Token::LeftShift => return Some(impl_op!(INT => shift_left(as_int, as_int))),
|
LeftShift => return Some(impl_op!(INT => shift_left(as_int, as_int))),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "unchecked")]
|
#[cfg(feature = "unchecked")]
|
||||||
match op {
|
match op {
|
||||||
Token::Plus => return Some(impl_op!(INT => as_int + as_int)),
|
Plus => return Some(impl_op!(INT => as_int + as_int)),
|
||||||
Token::Minus => return Some(impl_op!(INT => as_int - as_int)),
|
Minus => return Some(impl_op!(INT => as_int - as_int)),
|
||||||
Token::Multiply => return Some(impl_op!(INT => as_int * as_int)),
|
Multiply => return Some(impl_op!(INT => as_int * as_int)),
|
||||||
Token::Divide => return Some(impl_op!(INT => as_int / as_int)),
|
Divide => return Some(impl_op!(INT => as_int / as_int)),
|
||||||
Token::Modulo => return Some(impl_op!(INT => as_int % as_int)),
|
Modulo => return Some(impl_op!(INT => as_int % as_int)),
|
||||||
Token::PowerOf => return Some(impl_op!(INT => as_int.pow(as_int as u32))),
|
PowerOf => return Some(impl_op!(INT => as_int.pow(as_int as u32))),
|
||||||
Token::RightShift => return Some(impl_op!(INT => as_int >> as_int)),
|
RightShift => return Some(impl_op!(INT => as_int >> as_int)),
|
||||||
Token::LeftShift => return Some(impl_op!(INT => as_int << as_int)),
|
LeftShift => return Some(impl_op!(INT => as_int << as_int)),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
return match op {
|
return match op {
|
||||||
Token::EqualsTo => Some(impl_op!(INT => as_int == as_int)),
|
EqualsTo => Some(impl_op!(INT => as_int == as_int)),
|
||||||
Token::NotEqualsTo => Some(impl_op!(INT => as_int != as_int)),
|
NotEqualsTo => Some(impl_op!(INT => as_int != as_int)),
|
||||||
Token::GreaterThan => Some(impl_op!(INT => as_int > as_int)),
|
GreaterThan => Some(impl_op!(INT => as_int > as_int)),
|
||||||
Token::GreaterThanEqualsTo => Some(impl_op!(INT => as_int >= as_int)),
|
GreaterThanEqualsTo => Some(impl_op!(INT => as_int >= as_int)),
|
||||||
Token::LessThan => Some(impl_op!(INT => as_int < as_int)),
|
LessThan => Some(impl_op!(INT => as_int < as_int)),
|
||||||
Token::LessThanEqualsTo => Some(impl_op!(INT => as_int <= as_int)),
|
LessThanEqualsTo => Some(impl_op!(INT => as_int <= as_int)),
|
||||||
Token::Ampersand => Some(impl_op!(INT => as_int & as_int)),
|
Ampersand => Some(impl_op!(INT => as_int & as_int)),
|
||||||
Token::Pipe => Some(impl_op!(INT => as_int | as_int)),
|
Pipe => Some(impl_op!(INT => as_int | as_int)),
|
||||||
Token::XOr => Some(impl_op!(INT => as_int ^ as_int)),
|
XOr => Some(impl_op!(INT => as_int ^ as_int)),
|
||||||
Token::ExclusiveRange => Some(|_, args| {
|
ExclusiveRange => Some(|_, args| {
|
||||||
let x = args[0].as_int().expect(BUILTIN);
|
let x = args[0].as_int().expect(BUILTIN);
|
||||||
let y = args[1].as_int().expect(BUILTIN);
|
let y = args[1].as_int().expect(BUILTIN);
|
||||||
Ok((x..y).into())
|
Ok((x..y).into())
|
||||||
}),
|
}),
|
||||||
Token::InclusiveRange => Some(|_, args| {
|
InclusiveRange => Some(|_, args| {
|
||||||
let x = args[0].as_int().expect(BUILTIN);
|
let x = args[0].as_int().expect(BUILTIN);
|
||||||
let y = args[1].as_int().expect(BUILTIN);
|
let y = args[1].as_int().expect(BUILTIN);
|
||||||
Ok((x..=y).into())
|
Ok((x..=y).into())
|
||||||
@ -181,46 +196,65 @@ pub fn get_builtin_binary_op_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Option<
|
|||||||
|
|
||||||
if type1 == TypeId::of::<bool>() {
|
if type1 == TypeId::of::<bool>() {
|
||||||
return match op {
|
return match op {
|
||||||
Token::EqualsTo => Some(impl_op!(bool => as_bool == as_bool)),
|
EqualsTo => Some(impl_op!(bool => as_bool == as_bool)),
|
||||||
Token::NotEqualsTo => Some(impl_op!(bool => as_bool != as_bool)),
|
NotEqualsTo => Some(impl_op!(bool => as_bool != as_bool)),
|
||||||
Token::GreaterThan => Some(impl_op!(bool => as_bool > as_bool)),
|
GreaterThan => Some(impl_op!(bool => as_bool > as_bool)),
|
||||||
Token::GreaterThanEqualsTo => Some(impl_op!(bool => as_bool >= as_bool)),
|
GreaterThanEqualsTo => Some(impl_op!(bool => as_bool >= as_bool)),
|
||||||
Token::LessThan => Some(impl_op!(bool => as_bool < as_bool)),
|
LessThan => Some(impl_op!(bool => as_bool < as_bool)),
|
||||||
Token::LessThanEqualsTo => Some(impl_op!(bool => as_bool <= as_bool)),
|
LessThanEqualsTo => Some(impl_op!(bool => as_bool <= as_bool)),
|
||||||
Token::Ampersand => Some(impl_op!(bool => as_bool & as_bool)),
|
Ampersand => Some(impl_op!(bool => as_bool & as_bool)),
|
||||||
Token::Pipe => Some(impl_op!(bool => as_bool | as_bool)),
|
Pipe => Some(impl_op!(bool => as_bool | as_bool)),
|
||||||
Token::XOr => Some(impl_op!(bool => as_bool ^ as_bool)),
|
XOr => Some(impl_op!(bool => as_bool ^ as_bool)),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if type1 == TypeId::of::<ImmutableString>() {
|
if type1 == TypeId::of::<ImmutableString>() {
|
||||||
return match op {
|
return match op {
|
||||||
Token::Plus => Some(impl_op!(ImmutableString + ImmutableString)),
|
Plus => Some(|_ctx, args| {
|
||||||
Token::Minus => Some(impl_op!(ImmutableString - ImmutableString)),
|
let s1 = &*args[0].read_lock::<ImmutableString>().expect(BUILTIN);
|
||||||
Token::EqualsTo => Some(impl_op!(ImmutableString == ImmutableString)),
|
let s2 = &*args[1].read_lock::<ImmutableString>().expect(BUILTIN);
|
||||||
Token::NotEqualsTo => Some(impl_op!(ImmutableString != ImmutableString)),
|
|
||||||
Token::GreaterThan => Some(impl_op!(ImmutableString > ImmutableString)),
|
#[cfg(not(feature = "unchecked"))]
|
||||||
Token::GreaterThanEqualsTo => Some(impl_op!(ImmutableString >= ImmutableString)),
|
if !s1.is_empty() && !s2.is_empty() {
|
||||||
Token::LessThan => Some(impl_op!(ImmutableString < ImmutableString)),
|
let total_len = s1.len() + s2.len();
|
||||||
Token::LessThanEqualsTo => Some(impl_op!(ImmutableString <= ImmutableString)),
|
_ctx.engine()
|
||||||
|
.raise_err_if_over_data_size_limit((0, 0, total_len))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok((s1 + s2).into())
|
||||||
|
}),
|
||||||
|
Minus => Some(impl_op!(ImmutableString - ImmutableString)),
|
||||||
|
EqualsTo => Some(impl_op!(ImmutableString == ImmutableString)),
|
||||||
|
NotEqualsTo => Some(impl_op!(ImmutableString != ImmutableString)),
|
||||||
|
GreaterThan => Some(impl_op!(ImmutableString > ImmutableString)),
|
||||||
|
GreaterThanEqualsTo => Some(impl_op!(ImmutableString >= ImmutableString)),
|
||||||
|
LessThan => Some(impl_op!(ImmutableString < ImmutableString)),
|
||||||
|
LessThanEqualsTo => Some(impl_op!(ImmutableString <= ImmutableString)),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if type1 == TypeId::of::<char>() {
|
if type1 == TypeId::of::<char>() {
|
||||||
return match op {
|
return match op {
|
||||||
Token::Plus => Some(|_, args| {
|
Plus => Some(|_ctx, args| {
|
||||||
let x = args[0].as_char().expect(BUILTIN);
|
let x = args[0].as_char().expect(BUILTIN);
|
||||||
let y = args[1].as_char().expect(BUILTIN);
|
let y = args[1].as_char().expect(BUILTIN);
|
||||||
Ok(format!("{x}{y}").into())
|
|
||||||
|
let result = format!("{x}{y}");
|
||||||
|
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
_ctx.engine()
|
||||||
|
.raise_err_if_over_data_size_limit((0, 0, result.len()))?;
|
||||||
|
|
||||||
|
Ok(result.into())
|
||||||
}),
|
}),
|
||||||
Token::EqualsTo => Some(impl_op!(char => as_char == as_char)),
|
EqualsTo => Some(impl_op!(char => as_char == as_char)),
|
||||||
Token::NotEqualsTo => Some(impl_op!(char => as_char != as_char)),
|
NotEqualsTo => Some(impl_op!(char => as_char != as_char)),
|
||||||
Token::GreaterThan => Some(impl_op!(char => as_char > as_char)),
|
GreaterThan => Some(impl_op!(char => as_char > as_char)),
|
||||||
Token::GreaterThanEqualsTo => Some(impl_op!(char => as_char >= as_char)),
|
GreaterThanEqualsTo => Some(impl_op!(char => as_char >= as_char)),
|
||||||
Token::LessThan => Some(impl_op!(char => as_char < as_char)),
|
LessThan => Some(impl_op!(char => as_char < as_char)),
|
||||||
Token::LessThanEqualsTo => Some(impl_op!(char => as_char <= as_char)),
|
LessThanEqualsTo => Some(impl_op!(char => as_char <= as_char)),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -230,7 +264,7 @@ pub fn get_builtin_binary_op_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Option<
|
|||||||
use crate::Blob;
|
use crate::Blob;
|
||||||
|
|
||||||
return match op {
|
return match op {
|
||||||
Token::Plus => Some(|_, args| {
|
Plus => Some(|_ctx, args| {
|
||||||
let blob1 = &*args[0].read_lock::<Blob>().expect(BUILTIN);
|
let blob1 = &*args[0].read_lock::<Blob>().expect(BUILTIN);
|
||||||
let blob2 = &*args[1].read_lock::<Blob>().expect(BUILTIN);
|
let blob2 = &*args[1].read_lock::<Blob>().expect(BUILTIN);
|
||||||
|
|
||||||
@ -239,25 +273,30 @@ pub fn get_builtin_binary_op_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Option<
|
|||||||
} else if blob1.is_empty() {
|
} else if blob1.is_empty() {
|
||||||
blob2.clone()
|
blob2.clone()
|
||||||
} else {
|
} else {
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
_ctx.engine().raise_err_if_over_data_size_limit((
|
||||||
|
blob1.len() + blob2.len(),
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
))?;
|
||||||
|
|
||||||
let mut blob = blob1.clone();
|
let mut blob = blob1.clone();
|
||||||
blob.extend(blob2);
|
blob.extend(blob2);
|
||||||
blob
|
blob
|
||||||
}))
|
}))
|
||||||
}),
|
}),
|
||||||
Token::EqualsTo => Some(impl_op!(Blob == Blob)),
|
EqualsTo => Some(impl_op!(Blob == Blob)),
|
||||||
Token::NotEqualsTo => Some(impl_op!(Blob != Blob)),
|
NotEqualsTo => Some(impl_op!(Blob != Blob)),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if type1 == TypeId::of::<()>() {
|
if type1 == TypeId::of::<()>() {
|
||||||
return match op {
|
return match op {
|
||||||
Token::EqualsTo => Some(|_, _| Ok(Dynamic::TRUE)),
|
EqualsTo => Some(const_true_fn),
|
||||||
Token::NotEqualsTo
|
NotEqualsTo | GreaterThan | GreaterThanEqualsTo | LessThan | LessThanEqualsTo => {
|
||||||
| Token::GreaterThan
|
Some(const_false_fn)
|
||||||
| Token::GreaterThanEqualsTo
|
}
|
||||||
| Token::LessThan
|
|
||||||
| Token::LessThanEqualsTo => Some(|_, _| Ok(Dynamic::FALSE)),
|
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -268,19 +307,19 @@ pub fn get_builtin_binary_op_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Option<
|
|||||||
($x:ty, $xx:ident, $y:ty, $yy:ident) => {
|
($x:ty, $xx:ident, $y:ty, $yy:ident) => {
|
||||||
if (type1, type2) == (TypeId::of::<$x>(), TypeId::of::<$y>()) {
|
if (type1, type2) == (TypeId::of::<$x>(), TypeId::of::<$y>()) {
|
||||||
return match op {
|
return match op {
|
||||||
Token::Plus => Some(impl_op!(FLOAT => $xx + $yy)),
|
Plus => Some(impl_op!(FLOAT => $xx + $yy)),
|
||||||
Token::Minus => Some(impl_op!(FLOAT => $xx - $yy)),
|
Minus => Some(impl_op!(FLOAT => $xx - $yy)),
|
||||||
Token::Multiply => Some(impl_op!(FLOAT => $xx * $yy)),
|
Multiply => Some(impl_op!(FLOAT => $xx * $yy)),
|
||||||
Token::Divide => Some(impl_op!(FLOAT => $xx / $yy)),
|
Divide => Some(impl_op!(FLOAT => $xx / $yy)),
|
||||||
Token::Modulo => Some(impl_op!(FLOAT => $xx % $yy)),
|
Modulo => Some(impl_op!(FLOAT => $xx % $yy)),
|
||||||
Token::PowerOf => Some(impl_op!(FLOAT => $xx.powf($yy as FLOAT))),
|
PowerOf => Some(impl_op!(FLOAT => $xx.powf($yy as FLOAT))),
|
||||||
Token::EqualsTo => Some(impl_op!(FLOAT => $xx == $yy)),
|
EqualsTo => Some(impl_op!(FLOAT => $xx == $yy)),
|
||||||
Token::NotEqualsTo => Some(impl_op!(FLOAT => $xx != $yy)),
|
NotEqualsTo => Some(impl_op!(FLOAT => $xx != $yy)),
|
||||||
Token::GreaterThan => Some(impl_op!(FLOAT => $xx > $yy)),
|
GreaterThan => Some(impl_op!(FLOAT => $xx > $yy)),
|
||||||
Token::GreaterThanEqualsTo => Some(impl_op!(FLOAT => $xx >= $yy)),
|
GreaterThanEqualsTo => Some(impl_op!(FLOAT => $xx >= $yy)),
|
||||||
Token::LessThan => Some(impl_op!(FLOAT => $xx < $yy)),
|
LessThan => Some(impl_op!(FLOAT => $xx < $yy)),
|
||||||
Token::LessThanEqualsTo => Some(impl_op!(FLOAT => $xx <= $yy)),
|
LessThanEqualsTo => Some(impl_op!(FLOAT => $xx <= $yy)),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -302,13 +341,13 @@ pub fn get_builtin_binary_op_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Option<
|
|||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
match op {
|
match op {
|
||||||
Token::Plus => return Some(impl_op!(from Decimal => add($xx, $yy))),
|
Plus => return Some(impl_op!(from Decimal => add($xx, $yy))),
|
||||||
Token::Minus => return Some(impl_op!(from Decimal => subtract($xx, $yy))),
|
Minus => return Some(impl_op!(from Decimal => subtract($xx, $yy))),
|
||||||
Token::Multiply => return Some(impl_op!(from Decimal => multiply($xx, $yy))),
|
Multiply => return Some(impl_op!(from Decimal => multiply($xx, $yy))),
|
||||||
Token::Divide => return Some(impl_op!(from Decimal => divide($xx, $yy))),
|
Divide => return Some(impl_op!(from Decimal => divide($xx, $yy))),
|
||||||
Token::Modulo => return Some(impl_op!(from Decimal => modulo($xx, $yy))),
|
Modulo => return Some(impl_op!(from Decimal => modulo($xx, $yy))),
|
||||||
Token::PowerOf => return Some(impl_op!(from Decimal => power($xx, $yy))),
|
PowerOf => return Some(impl_op!(from Decimal => power($xx, $yy))),
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "unchecked")]
|
#[cfg(feature = "unchecked")]
|
||||||
@ -316,23 +355,23 @@ pub fn get_builtin_binary_op_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Option<
|
|||||||
|
|
||||||
#[cfg(feature = "unchecked")]
|
#[cfg(feature = "unchecked")]
|
||||||
match op {
|
match op {
|
||||||
Token::Plus => return Some(impl_op!(from Decimal => $xx + $yy)),
|
Plus => return Some(impl_op!(from Decimal => $xx + $yy)),
|
||||||
Token::Minus => return Some(impl_op!(from Decimal => $xx - $yy)),
|
Minus => return Some(impl_op!(from Decimal => $xx - $yy)),
|
||||||
Token::Multiply => return Some(impl_op!(from Decimal => $xx * $yy)),
|
Multiply => return Some(impl_op!(from Decimal => $xx * $yy)),
|
||||||
Token::Divide => return Some(impl_op!(from Decimal => $xx / $yy)),
|
Divide => return Some(impl_op!(from Decimal => $xx / $yy)),
|
||||||
Token::Modulo => return Some(impl_op!(from Decimal => $xx % $yy)),
|
Modulo => return Some(impl_op!(from Decimal => $xx % $yy)),
|
||||||
Token::PowerOf => return Some(impl_op!(from Decimal => $xx.powd($yy))),
|
PowerOf => return Some(impl_op!(from Decimal => $xx.powd($yy))),
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
|
|
||||||
return match op {
|
return match op {
|
||||||
Token::EqualsTo => Some(impl_op!(from Decimal => $xx == $yy)),
|
EqualsTo => Some(impl_op!(from Decimal => $xx == $yy)),
|
||||||
Token::NotEqualsTo => Some(impl_op!(from Decimal => $xx != $yy)),
|
NotEqualsTo => Some(impl_op!(from Decimal => $xx != $yy)),
|
||||||
Token::GreaterThan => Some(impl_op!(from Decimal => $xx > $yy)),
|
GreaterThan => Some(impl_op!(from Decimal => $xx > $yy)),
|
||||||
Token::GreaterThanEqualsTo => Some(impl_op!(from Decimal => $xx >= $yy)),
|
GreaterThanEqualsTo => Some(impl_op!(from Decimal => $xx >= $yy)),
|
||||||
Token::LessThan => Some(impl_op!(from Decimal => $xx < $yy)),
|
LessThan => Some(impl_op!(from Decimal => $xx < $yy)),
|
||||||
Token::LessThanEqualsTo => Some(impl_op!(from Decimal => $xx <= $yy)),
|
LessThanEqualsTo => Some(impl_op!(from Decimal => $xx <= $yy)),
|
||||||
_ => None
|
_ => None
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -357,17 +396,23 @@ pub fn get_builtin_binary_op_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Option<
|
|||||||
}
|
}
|
||||||
|
|
||||||
return match op {
|
return match op {
|
||||||
Token::Plus => Some(|_, args| {
|
Plus => Some(|_ctx, args| {
|
||||||
let x = args[0].as_char().expect(BUILTIN);
|
let x = args[0].as_char().expect(BUILTIN);
|
||||||
let y = &*args[1].read_lock::<ImmutableString>().expect(BUILTIN);
|
let y = &*args[1].read_lock::<ImmutableString>().expect(BUILTIN);
|
||||||
Ok(format!("{x}{y}").into())
|
let result = format!("{x}{y}");
|
||||||
|
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
_ctx.engine()
|
||||||
|
.raise_err_if_over_data_size_limit((0, 0, result.len()))?;
|
||||||
|
|
||||||
|
Ok(result.into())
|
||||||
}),
|
}),
|
||||||
Token::EqualsTo => Some(impl_op!(get_s1s2(==))),
|
EqualsTo => Some(impl_op!(get_s1s2(==))),
|
||||||
Token::NotEqualsTo => Some(impl_op!(get_s1s2(!=))),
|
NotEqualsTo => Some(impl_op!(get_s1s2(!=))),
|
||||||
Token::GreaterThan => Some(impl_op!(get_s1s2(>))),
|
GreaterThan => Some(impl_op!(get_s1s2(>))),
|
||||||
Token::GreaterThanEqualsTo => Some(impl_op!(get_s1s2(>=))),
|
GreaterThanEqualsTo => Some(impl_op!(get_s1s2(>=))),
|
||||||
Token::LessThan => Some(impl_op!(get_s1s2(<))),
|
LessThan => Some(impl_op!(get_s1s2(<))),
|
||||||
Token::LessThanEqualsTo => Some(impl_op!(get_s1s2(<=))),
|
LessThanEqualsTo => Some(impl_op!(get_s1s2(<=))),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -383,48 +428,50 @@ pub fn get_builtin_binary_op_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Option<
|
|||||||
}
|
}
|
||||||
|
|
||||||
return match op {
|
return match op {
|
||||||
Token::Plus => Some(|_, args| {
|
Plus => Some(|_ctx, args| {
|
||||||
let x = &*args[0].read_lock::<ImmutableString>().expect(BUILTIN);
|
let x = &*args[0].read_lock::<ImmutableString>().expect(BUILTIN);
|
||||||
let y = args[1].as_char().expect(BUILTIN);
|
let y = args[1].as_char().expect(BUILTIN);
|
||||||
Ok((x + y).into())
|
let result = x + y;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
_ctx.engine()
|
||||||
|
.raise_err_if_over_data_size_limit((0, 0, result.len()))?;
|
||||||
|
|
||||||
|
Ok(result.into())
|
||||||
}),
|
}),
|
||||||
Token::Minus => Some(|_, args| {
|
Minus => Some(|_, args| {
|
||||||
let x = &*args[0].read_lock::<ImmutableString>().expect(BUILTIN);
|
let x = &*args[0].read_lock::<ImmutableString>().expect(BUILTIN);
|
||||||
let y = args[1].as_char().expect(BUILTIN);
|
let y = args[1].as_char().expect(BUILTIN);
|
||||||
Ok((x - y).into())
|
Ok((x - y).into())
|
||||||
}),
|
}),
|
||||||
Token::EqualsTo => Some(impl_op!(get_s1s2(==))),
|
EqualsTo => Some(impl_op!(get_s1s2(==))),
|
||||||
Token::NotEqualsTo => Some(impl_op!(get_s1s2(!=))),
|
NotEqualsTo => Some(impl_op!(get_s1s2(!=))),
|
||||||
Token::GreaterThan => Some(impl_op!(get_s1s2(>))),
|
GreaterThan => Some(impl_op!(get_s1s2(>))),
|
||||||
Token::GreaterThanEqualsTo => Some(impl_op!(get_s1s2(>=))),
|
GreaterThanEqualsTo => Some(impl_op!(get_s1s2(>=))),
|
||||||
Token::LessThan => Some(impl_op!(get_s1s2(<))),
|
LessThan => Some(impl_op!(get_s1s2(<))),
|
||||||
Token::LessThanEqualsTo => Some(impl_op!(get_s1s2(<=))),
|
LessThanEqualsTo => Some(impl_op!(get_s1s2(<=))),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// () op string
|
// () op string
|
||||||
if (type1, type2) == (TypeId::of::<()>(), TypeId::of::<ImmutableString>()) {
|
if (type1, type2) == (TypeId::of::<()>(), TypeId::of::<ImmutableString>()) {
|
||||||
return match op {
|
return match op {
|
||||||
Token::Plus => Some(|_, args| Ok(args[1].clone())),
|
Plus => Some(|_, args| Ok(args[1].clone())),
|
||||||
Token::EqualsTo
|
EqualsTo | GreaterThan | GreaterThanEqualsTo | LessThan | LessThanEqualsTo => {
|
||||||
| Token::GreaterThan
|
Some(const_false_fn)
|
||||||
| Token::GreaterThanEqualsTo
|
}
|
||||||
| Token::LessThan
|
NotEqualsTo => Some(const_true_fn),
|
||||||
| Token::LessThanEqualsTo => Some(|_, _| Ok(Dynamic::FALSE)),
|
|
||||||
Token::NotEqualsTo => Some(|_, _| Ok(Dynamic::TRUE)),
|
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// string op ()
|
// string op ()
|
||||||
if (type1, type2) == (TypeId::of::<ImmutableString>(), TypeId::of::<()>()) {
|
if (type1, type2) == (TypeId::of::<ImmutableString>(), TypeId::of::<()>()) {
|
||||||
return match op {
|
return match op {
|
||||||
Token::Plus => Some(|_, args| Ok(args[0].clone())),
|
Plus => Some(|_, args| Ok(args[0].clone())),
|
||||||
Token::EqualsTo
|
EqualsTo | GreaterThan | GreaterThanEqualsTo | LessThan | LessThanEqualsTo => {
|
||||||
| Token::GreaterThan
|
Some(const_false_fn)
|
||||||
| Token::GreaterThanEqualsTo
|
}
|
||||||
| Token::LessThan
|
NotEqualsTo => Some(const_true_fn),
|
||||||
| Token::LessThanEqualsTo => Some(|_, _| Ok(Dynamic::FALSE)),
|
|
||||||
Token::NotEqualsTo => Some(|_, _| Ok(Dynamic::TRUE)),
|
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -436,10 +483,18 @@ pub fn get_builtin_binary_op_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Option<
|
|||||||
|
|
||||||
if type2 == TypeId::of::<char>() {
|
if type2 == TypeId::of::<char>() {
|
||||||
return match op {
|
return match op {
|
||||||
Token::Plus => Some(|_, args| {
|
Plus => Some(|_ctx, args| {
|
||||||
let mut buf = [0_u8; 4];
|
|
||||||
let mut blob = args[0].read_lock::<Blob>().expect(BUILTIN).clone();
|
let mut blob = args[0].read_lock::<Blob>().expect(BUILTIN).clone();
|
||||||
let x = args[1].as_char().expect("`char`").encode_utf8(&mut buf);
|
let mut buf = [0_u8; 4];
|
||||||
|
let x = args[1].as_char().expect(BUILTIN).encode_utf8(&mut buf);
|
||||||
|
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
_ctx.engine().raise_err_if_over_data_size_limit((
|
||||||
|
blob.len() + x.len(),
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
))?;
|
||||||
|
|
||||||
blob.extend(x.as_bytes());
|
blob.extend(x.as_bytes());
|
||||||
Ok(Dynamic::from_blob(blob))
|
Ok(Dynamic::from_blob(blob))
|
||||||
}),
|
}),
|
||||||
@ -461,8 +516,8 @@ pub fn get_builtin_binary_op_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Option<
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
return match op {
|
return match op {
|
||||||
Token::NotEqualsTo => Some(|_, _| Ok(Dynamic::TRUE)),
|
NotEqualsTo => Some(const_true_fn),
|
||||||
Token::Equals => Some(|_, _| Ok(Dynamic::FALSE)),
|
Equals => Some(const_false_fn),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -471,8 +526,8 @@ pub fn get_builtin_binary_op_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Option<
|
|||||||
if type1 == TypeId::of::<ExclusiveRange>() {
|
if type1 == TypeId::of::<ExclusiveRange>() {
|
||||||
if type1 == type2 {
|
if type1 == type2 {
|
||||||
return match op {
|
return match op {
|
||||||
Token::EqualsTo => Some(impl_op!(ExclusiveRange == ExclusiveRange)),
|
EqualsTo => Some(impl_op!(ExclusiveRange == ExclusiveRange)),
|
||||||
Token::NotEqualsTo => Some(impl_op!(ExclusiveRange != ExclusiveRange)),
|
NotEqualsTo => Some(impl_op!(ExclusiveRange != ExclusiveRange)),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -481,8 +536,8 @@ pub fn get_builtin_binary_op_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Option<
|
|||||||
if type1 == TypeId::of::<InclusiveRange>() {
|
if type1 == TypeId::of::<InclusiveRange>() {
|
||||||
if type1 == type2 {
|
if type1 == type2 {
|
||||||
return match op {
|
return match op {
|
||||||
Token::EqualsTo => Some(impl_op!(InclusiveRange == InclusiveRange)),
|
EqualsTo => Some(impl_op!(InclusiveRange == InclusiveRange)),
|
||||||
Token::NotEqualsTo => Some(impl_op!(InclusiveRange != InclusiveRange)),
|
NotEqualsTo => Some(impl_op!(InclusiveRange != InclusiveRange)),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -496,12 +551,10 @@ pub fn get_builtin_binary_op_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Option<
|
|||||||
} else if type1 != type2 {
|
} else if type1 != type2 {
|
||||||
// If the types are not the same, default to not compare
|
// If the types are not the same, default to not compare
|
||||||
match op {
|
match op {
|
||||||
Token::NotEqualsTo => Some(|_, _| Ok(Dynamic::TRUE)),
|
NotEqualsTo => Some(const_true_fn),
|
||||||
Token::EqualsTo
|
EqualsTo | GreaterThan | GreaterThanEqualsTo | LessThan | LessThanEqualsTo => {
|
||||||
| Token::GreaterThan
|
Some(const_false_fn)
|
||||||
| Token::GreaterThanEqualsTo
|
}
|
||||||
| Token::LessThan
|
|
||||||
| Token::LessThanEqualsTo => Some(|_, _| Ok(Dynamic::FALSE)),
|
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -513,12 +566,10 @@ pub fn get_builtin_binary_op_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Option<
|
|||||||
// Default comparison operators for different types
|
// Default comparison operators for different types
|
||||||
if type2 != type1 {
|
if type2 != type1 {
|
||||||
return match op {
|
return match op {
|
||||||
Token::NotEqualsTo => Some(|_, _| Ok(Dynamic::TRUE)),
|
NotEqualsTo => Some(const_true_fn),
|
||||||
Token::EqualsTo
|
EqualsTo | GreaterThan | GreaterThanEqualsTo | LessThan | LessThanEqualsTo => {
|
||||||
| Token::GreaterThan
|
Some(const_false_fn)
|
||||||
| Token::GreaterThanEqualsTo
|
}
|
||||||
| Token::LessThan
|
|
||||||
| Token::LessThanEqualsTo => Some(|_, _| Ok(Dynamic::FALSE)),
|
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -583,51 +634,49 @@ pub fn get_builtin_op_assignment_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Opt
|
|||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
match op {
|
match op {
|
||||||
Token::PlusAssign => return Some(impl_op!(INT => add(as_int, as_int))),
|
PlusAssign => return Some(impl_op!(INT => add(as_int, as_int))),
|
||||||
Token::MinusAssign => return Some(impl_op!(INT => subtract(as_int, as_int))),
|
MinusAssign => return Some(impl_op!(INT => subtract(as_int, as_int))),
|
||||||
Token::MultiplyAssign => return Some(impl_op!(INT => multiply(as_int, as_int))),
|
MultiplyAssign => return Some(impl_op!(INT => multiply(as_int, as_int))),
|
||||||
Token::DivideAssign => return Some(impl_op!(INT => divide(as_int, as_int))),
|
DivideAssign => return Some(impl_op!(INT => divide(as_int, as_int))),
|
||||||
Token::ModuloAssign => return Some(impl_op!(INT => modulo(as_int, as_int))),
|
ModuloAssign => return Some(impl_op!(INT => modulo(as_int, as_int))),
|
||||||
Token::PowerOfAssign => return Some(impl_op!(INT => power(as_int, as_int))),
|
PowerOfAssign => return Some(impl_op!(INT => power(as_int, as_int))),
|
||||||
Token::RightShiftAssign => {
|
RightShiftAssign => return Some(impl_op!(INT => shift_right(as_int, as_int))),
|
||||||
return Some(impl_op!(INT => shift_right(as_int, as_int)))
|
LeftShiftAssign => return Some(impl_op!(INT => shift_left(as_int, as_int))),
|
||||||
}
|
|
||||||
Token::LeftShiftAssign => return Some(impl_op!(INT => shift_left(as_int, as_int))),
|
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "unchecked")]
|
#[cfg(feature = "unchecked")]
|
||||||
match op {
|
match op {
|
||||||
Token::PlusAssign => return Some(impl_op!(INT += as_int)),
|
PlusAssign => return Some(impl_op!(INT += as_int)),
|
||||||
Token::MinusAssign => return Some(impl_op!(INT -= as_int)),
|
MinusAssign => return Some(impl_op!(INT -= as_int)),
|
||||||
Token::MultiplyAssign => return Some(impl_op!(INT *= as_int)),
|
MultiplyAssign => return Some(impl_op!(INT *= as_int)),
|
||||||
Token::DivideAssign => return Some(impl_op!(INT /= as_int)),
|
DivideAssign => return Some(impl_op!(INT /= as_int)),
|
||||||
Token::ModuloAssign => return Some(impl_op!(INT %= as_int)),
|
ModuloAssign => return Some(impl_op!(INT %= as_int)),
|
||||||
Token::PowerOfAssign => return Some(impl_op!(INT => as_int.pow(as_int as u32))),
|
PowerOfAssign => return Some(impl_op!(INT => as_int.pow(as_int as u32))),
|
||||||
Token::RightShiftAssign => return Some(impl_op!(INT >>= as_int)),
|
RightShiftAssign => return Some(impl_op!(INT >>= as_int)),
|
||||||
Token::LeftShiftAssign => return Some(impl_op!(INT <<= as_int)),
|
LeftShiftAssign => return Some(impl_op!(INT <<= as_int)),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
return match op {
|
return match op {
|
||||||
Token::AndAssign => Some(impl_op!(INT &= as_int)),
|
AndAssign => Some(impl_op!(INT &= as_int)),
|
||||||
Token::OrAssign => Some(impl_op!(INT |= as_int)),
|
OrAssign => Some(impl_op!(INT |= as_int)),
|
||||||
Token::XOrAssign => Some(impl_op!(INT ^= as_int)),
|
XOrAssign => Some(impl_op!(INT ^= as_int)),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if type1 == TypeId::of::<bool>() {
|
if type1 == TypeId::of::<bool>() {
|
||||||
return match op {
|
return match op {
|
||||||
Token::AndAssign => Some(impl_op!(bool = x && as_bool)),
|
AndAssign => Some(impl_op!(bool = x && as_bool)),
|
||||||
Token::OrAssign => Some(impl_op!(bool = x || as_bool)),
|
OrAssign => Some(impl_op!(bool = x || as_bool)),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if type1 == TypeId::of::<char>() {
|
if type1 == TypeId::of::<char>() {
|
||||||
return match op {
|
return match op {
|
||||||
Token::PlusAssign => Some(|_, args| {
|
PlusAssign => Some(|_, args| {
|
||||||
let y = args[1].as_char().expect(BUILTIN);
|
let y = args[1].as_char().expect(BUILTIN);
|
||||||
let x = &mut *args[0].write_lock::<Dynamic>().expect(BUILTIN);
|
let x = &mut *args[0].write_lock::<Dynamic>().expect(BUILTIN);
|
||||||
Ok((*x = format!("{x}{y}").into()).into())
|
Ok((*x = format!("{x}{y}").into()).into())
|
||||||
@ -638,13 +687,21 @@ pub fn get_builtin_op_assignment_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Opt
|
|||||||
|
|
||||||
if type1 == TypeId::of::<ImmutableString>() {
|
if type1 == TypeId::of::<ImmutableString>() {
|
||||||
return match op {
|
return match op {
|
||||||
Token::PlusAssign => Some(|_, args| {
|
PlusAssign => Some(|_ctx, args| {
|
||||||
let (first, second) = args.split_first_mut().expect(BUILTIN);
|
let (first, second) = args.split_first_mut().expect(BUILTIN);
|
||||||
let x = &mut *first.write_lock::<ImmutableString>().expect(BUILTIN);
|
let x = &mut *first.write_lock::<ImmutableString>().expect(BUILTIN);
|
||||||
let y = std::mem::take(second[0]).cast::<ImmutableString>();
|
let y = std::mem::take(second[0]).cast::<ImmutableString>();
|
||||||
|
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
if !x.is_empty() && !y.is_empty() {
|
||||||
|
let total_len = x.len() + y.len();
|
||||||
|
_ctx.engine()
|
||||||
|
.raise_err_if_over_data_size_limit((0, 0, total_len))?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok((*x += y).into())
|
Ok((*x += y).into())
|
||||||
}),
|
}),
|
||||||
Token::MinusAssign => Some(|_, args| {
|
MinusAssign => Some(|_, args| {
|
||||||
let (first, second) = args.split_first_mut().expect(BUILTIN);
|
let (first, second) = args.split_first_mut().expect(BUILTIN);
|
||||||
let x = &mut *first.write_lock::<ImmutableString>().expect(BUILTIN);
|
let x = &mut *first.write_lock::<ImmutableString>().expect(BUILTIN);
|
||||||
let y = std::mem::take(second[0]).cast::<ImmutableString>();
|
let y = std::mem::take(second[0]).cast::<ImmutableString>();
|
||||||
@ -654,15 +711,55 @@ pub fn get_builtin_op_assignment_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Opt
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
if type1 == TypeId::of::<crate::Array>() {
|
||||||
|
use crate::packages::array_basic::array_functions::*;
|
||||||
|
use crate::Array;
|
||||||
|
|
||||||
|
return match op {
|
||||||
|
PlusAssign => Some(|_ctx, args| {
|
||||||
|
let x = std::mem::take(args[1]).cast::<Array>();
|
||||||
|
|
||||||
|
if x.is_empty() {
|
||||||
|
return Ok(Dynamic::UNIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
let _array_is_empty = args[0].read_lock::<Array>().expect(BUILTIN).is_empty();
|
||||||
|
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
if !_array_is_empty {
|
||||||
|
_ctx.engine().check_data_size(
|
||||||
|
&*args[0].read_lock().expect(BUILTIN),
|
||||||
|
crate::Position::NONE,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let array = &mut *args[0].write_lock::<Array>().expect(BUILTIN);
|
||||||
|
|
||||||
|
Ok(append(array, x).into())
|
||||||
|
}),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
if type1 == TypeId::of::<crate::Blob>() {
|
if type1 == TypeId::of::<crate::Blob>() {
|
||||||
|
use crate::packages::blob_basic::blob_functions::*;
|
||||||
use crate::Blob;
|
use crate::Blob;
|
||||||
|
|
||||||
return match op {
|
return match op {
|
||||||
Token::PlusAssign => Some(|_, args| {
|
PlusAssign => Some(|_ctx, args| {
|
||||||
let blob2 = std::mem::take(args[1]).cast::<Blob>();
|
let blob2 = std::mem::take(args[1]).cast::<Blob>();
|
||||||
let blob1 = &mut *args[0].write_lock::<Blob>().expect(BUILTIN);
|
let blob1 = &mut *args[0].write_lock::<Blob>().expect(BUILTIN);
|
||||||
Ok(crate::packages::blob_basic::blob_functions::append(blob1, blob2).into())
|
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
_ctx.engine().raise_err_if_over_data_size_limit((
|
||||||
|
blob1.len() + blob2.len(),
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
))?;
|
||||||
|
|
||||||
|
Ok(append(blob1, blob2).into())
|
||||||
}),
|
}),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
@ -674,13 +771,13 @@ pub fn get_builtin_op_assignment_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Opt
|
|||||||
($x:ident, $xx:ident, $y:ty, $yy:ident) => {
|
($x:ident, $xx:ident, $y:ty, $yy:ident) => {
|
||||||
if (type1, type2) == (TypeId::of::<$x>(), TypeId::of::<$y>()) {
|
if (type1, type2) == (TypeId::of::<$x>(), TypeId::of::<$y>()) {
|
||||||
return match op {
|
return match op {
|
||||||
Token::PlusAssign => Some(impl_op!($x += $yy)),
|
PlusAssign => Some(impl_op!($x += $yy)),
|
||||||
Token::MinusAssign => Some(impl_op!($x -= $yy)),
|
MinusAssign => Some(impl_op!($x -= $yy)),
|
||||||
Token::MultiplyAssign => Some(impl_op!($x *= $yy)),
|
MultiplyAssign => Some(impl_op!($x *= $yy)),
|
||||||
Token::DivideAssign => Some(impl_op!($x /= $yy)),
|
DivideAssign => Some(impl_op!($x /= $yy)),
|
||||||
Token::ModuloAssign => Some(impl_op!($x %= $yy)),
|
ModuloAssign => Some(impl_op!($x %= $yy)),
|
||||||
Token::PowerOfAssign => Some(impl_op!($x => $xx.powf($yy as $x))),
|
PowerOfAssign => Some(impl_op!($x => $xx.powf($yy as $x))),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -701,13 +798,13 @@ pub fn get_builtin_op_assignment_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Opt
|
|||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
return match op {
|
return match op {
|
||||||
Token::PlusAssign => Some(impl_op!(from $x => add($xx, $yy))),
|
PlusAssign => Some(impl_op!(from $x => add($xx, $yy))),
|
||||||
Token::MinusAssign => Some(impl_op!(from $x => subtract($xx, $yy))),
|
MinusAssign => Some(impl_op!(from $x => subtract($xx, $yy))),
|
||||||
Token::MultiplyAssign => Some(impl_op!(from $x => multiply($xx, $yy))),
|
MultiplyAssign => Some(impl_op!(from $x => multiply($xx, $yy))),
|
||||||
Token::DivideAssign => Some(impl_op!(from $x => divide($xx, $yy))),
|
DivideAssign => Some(impl_op!(from $x => divide($xx, $yy))),
|
||||||
Token::ModuloAssign => Some(impl_op!(from $x => modulo($xx, $yy))),
|
ModuloAssign => Some(impl_op!(from $x => modulo($xx, $yy))),
|
||||||
Token::PowerOfAssign => Some(impl_op!(from $x => power($xx, $yy))),
|
PowerOfAssign => Some(impl_op!(from $x => power($xx, $yy))),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "unchecked")]
|
#[cfg(feature = "unchecked")]
|
||||||
@ -715,13 +812,13 @@ pub fn get_builtin_op_assignment_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Opt
|
|||||||
|
|
||||||
#[cfg(feature = "unchecked")]
|
#[cfg(feature = "unchecked")]
|
||||||
return match op {
|
return match op {
|
||||||
Token::PlusAssign => Some(impl_op!(from $x += $yy)),
|
PlusAssign => Some(impl_op!(from $x += $yy)),
|
||||||
Token::MinusAssign => Some(impl_op!(from $x -= $yy)),
|
MinusAssign => Some(impl_op!(from $x -= $yy)),
|
||||||
Token::MultiplyAssign => Some(impl_op!(from $x *= $yy)),
|
MultiplyAssign => Some(impl_op!(from $x *= $yy)),
|
||||||
Token::DivideAssign => Some(impl_op!(from $x /= $yy)),
|
DivideAssign => Some(impl_op!(from $x /= $yy)),
|
||||||
Token::ModuloAssign => Some(impl_op!(from $x %= $yy)),
|
ModuloAssign => Some(impl_op!(from $x %= $yy)),
|
||||||
Token::PowerOfAssign => Some(impl_op!(from $x => $xx.powd($yy))),
|
PowerOfAssign => Some(impl_op!(from $x => $xx.powd($yy))),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -736,25 +833,45 @@ pub fn get_builtin_op_assignment_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Opt
|
|||||||
// string op= char
|
// string op= char
|
||||||
if (type1, type2) == (TypeId::of::<ImmutableString>(), TypeId::of::<char>()) {
|
if (type1, type2) == (TypeId::of::<ImmutableString>(), TypeId::of::<char>()) {
|
||||||
return match op {
|
return match op {
|
||||||
Token::PlusAssign => Some(impl_op!(ImmutableString += as_char as char)),
|
PlusAssign => Some(|_ctx, args| {
|
||||||
Token::MinusAssign => Some(impl_op!(ImmutableString -= as_char as char)),
|
let mut buf = [0_u8; 4];
|
||||||
|
let ch = &*args[1].as_char().expect(BUILTIN).encode_utf8(&mut buf);
|
||||||
|
let mut x = args[0].write_lock::<ImmutableString>().expect(BUILTIN);
|
||||||
|
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
_ctx.engine()
|
||||||
|
.raise_err_if_over_data_size_limit((0, 0, x.len() + ch.len()))?;
|
||||||
|
|
||||||
|
Ok((*x += ch).into())
|
||||||
|
}),
|
||||||
|
MinusAssign => Some(impl_op!(ImmutableString -= as_char as char)),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// char op= string
|
// char op= string
|
||||||
if (type1, type2) == (TypeId::of::<char>(), TypeId::of::<ImmutableString>()) {
|
if (type1, type2) == (TypeId::of::<char>(), TypeId::of::<ImmutableString>()) {
|
||||||
return match op {
|
return match op {
|
||||||
Token::PlusAssign => Some(|_, args| {
|
PlusAssign => Some(|_ctx, args| {
|
||||||
let mut ch = args[0].as_char().expect(BUILTIN).to_string();
|
let ch = {
|
||||||
ch.push_str(
|
let s = &*args[1].read_lock::<ImmutableString>().expect(BUILTIN);
|
||||||
args[1]
|
|
||||||
.read_lock::<ImmutableString>()
|
|
||||||
.expect(BUILTIN)
|
|
||||||
.as_str(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut x = args[0].write_lock::<Dynamic>().expect(BUILTIN);
|
if s.is_empty() {
|
||||||
Ok((*x = ch.into()).into())
|
return Ok(Dynamic::UNIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut ch = args[0].as_char().expect(BUILTIN).to_string();
|
||||||
|
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
_ctx.engine()
|
||||||
|
.raise_err_if_over_data_size_limit((0, 0, ch.len() + s.len()))?;
|
||||||
|
|
||||||
|
ch.push_str(s);
|
||||||
|
ch
|
||||||
|
};
|
||||||
|
|
||||||
|
*args[0].write_lock::<Dynamic>().expect(BUILTIN) = ch.into();
|
||||||
|
|
||||||
|
Ok(Dynamic::UNIT)
|
||||||
}),
|
}),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
@ -766,21 +883,21 @@ pub fn get_builtin_op_assignment_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Opt
|
|||||||
use crate::packages::array_basic::array_functions::*;
|
use crate::packages::array_basic::array_functions::*;
|
||||||
use crate::Array;
|
use crate::Array;
|
||||||
|
|
||||||
if type2 == TypeId::of::<crate::Array>() {
|
|
||||||
return match op {
|
|
||||||
Token::PlusAssign => Some(|_, args| {
|
|
||||||
let array2 = std::mem::take(args[1]).cast::<Array>();
|
|
||||||
let array1 = &mut *args[0].write_lock::<Array>().expect(BUILTIN);
|
|
||||||
Ok(append(array1, array2).into())
|
|
||||||
}),
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return match op {
|
return match op {
|
||||||
Token::PlusAssign => Some(|_, args| {
|
PlusAssign => Some(|_ctx, args| {
|
||||||
let x = std::mem::take(args[1]);
|
{
|
||||||
let array = &mut *args[0].write_lock::<Array>().expect(BUILTIN);
|
let x = std::mem::take(args[1]);
|
||||||
Ok(push(array, x).into())
|
let array = &mut *args[0].write_lock::<Array>().expect(BUILTIN);
|
||||||
|
push(array, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
_ctx.engine().check_data_size(
|
||||||
|
&*args[0].read_lock().expect(BUILTIN),
|
||||||
|
crate::Position::NONE,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(Dynamic::UNIT)
|
||||||
}),
|
}),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
@ -792,11 +909,18 @@ pub fn get_builtin_op_assignment_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Opt
|
|||||||
|
|
||||||
// blob op= int
|
// blob op= int
|
||||||
if (type1, type2) == (TypeId::of::<Blob>(), TypeId::of::<INT>()) {
|
if (type1, type2) == (TypeId::of::<Blob>(), TypeId::of::<INT>()) {
|
||||||
|
use crate::packages::blob_basic::blob_functions::*;
|
||||||
|
|
||||||
return match op {
|
return match op {
|
||||||
Token::PlusAssign => Some(|_, args| {
|
PlusAssign => Some(|_ctx, args| {
|
||||||
let x = args[1].as_int().expect("`INT`");
|
let x = args[1].as_int().expect(BUILTIN);
|
||||||
let blob = &mut *args[0].write_lock::<Blob>().expect(BUILTIN);
|
let blob = &mut *args[0].write_lock::<Blob>().expect(BUILTIN);
|
||||||
Ok(crate::packages::blob_basic::blob_functions::push(blob, x).into())
|
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
_ctx.engine()
|
||||||
|
.raise_err_if_over_data_size_limit((blob.len() + 1, 0, 0))?;
|
||||||
|
|
||||||
|
Ok(push(blob, x).into())
|
||||||
}),
|
}),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
@ -804,11 +928,18 @@ pub fn get_builtin_op_assignment_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Opt
|
|||||||
|
|
||||||
// blob op= char
|
// blob op= char
|
||||||
if (type1, type2) == (TypeId::of::<Blob>(), TypeId::of::<char>()) {
|
if (type1, type2) == (TypeId::of::<Blob>(), TypeId::of::<char>()) {
|
||||||
|
use crate::packages::blob_basic::blob_functions::*;
|
||||||
|
|
||||||
return match op {
|
return match op {
|
||||||
Token::PlusAssign => Some(|_, args| {
|
PlusAssign => Some(|_ctx, args| {
|
||||||
let x = args[1].as_char().expect("`char`");
|
let x = args[1].as_char().expect(BUILTIN);
|
||||||
let blob = &mut *args[0].write_lock::<Blob>().expect(BUILTIN);
|
let blob = &mut *args[0].write_lock::<Blob>().expect(BUILTIN);
|
||||||
Ok(crate::packages::blob_basic::blob_functions::append_char(blob, x).into())
|
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
_ctx.engine()
|
||||||
|
.raise_err_if_over_data_size_limit((blob.len() + 1, 0, 0))?;
|
||||||
|
|
||||||
|
Ok(append_char(blob, x).into())
|
||||||
}),
|
}),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
@ -816,11 +947,26 @@ pub fn get_builtin_op_assignment_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Opt
|
|||||||
|
|
||||||
// blob op= string
|
// blob op= string
|
||||||
if (type1, type2) == (TypeId::of::<Blob>(), TypeId::of::<ImmutableString>()) {
|
if (type1, type2) == (TypeId::of::<Blob>(), TypeId::of::<ImmutableString>()) {
|
||||||
|
use crate::packages::blob_basic::blob_functions::*;
|
||||||
|
|
||||||
return match op {
|
return match op {
|
||||||
Token::PlusAssign => Some(|_, args| {
|
PlusAssign => Some(|_ctx, args| {
|
||||||
let s = std::mem::take(args[1]).cast::<ImmutableString>();
|
let s = std::mem::take(args[1]).cast::<ImmutableString>();
|
||||||
|
|
||||||
|
if s.is_empty() {
|
||||||
|
return Ok(Dynamic::UNIT);
|
||||||
|
}
|
||||||
|
|
||||||
let blob = &mut *args[0].write_lock::<Blob>().expect(BUILTIN);
|
let blob = &mut *args[0].write_lock::<Blob>().expect(BUILTIN);
|
||||||
Ok(crate::packages::blob_basic::blob_functions::append_str(blob, &s).into())
|
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
_ctx.engine().raise_err_if_over_data_size_limit((
|
||||||
|
blob.len() + s.len(),
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
))?;
|
||||||
|
|
||||||
|
Ok(append_str(blob, &s).into())
|
||||||
}),
|
}),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
@ -258,9 +258,7 @@ impl Engine {
|
|||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
let is_dynamic = is_dynamic
|
let is_dynamic = is_dynamic
|
||||||
|| _global
|
|| _global.may_contain_dynamic_fn(hash_base)
|
||||||
.iter_imports_raw()
|
|
||||||
.any(|(_, m)| m.may_contain_dynamic_fn(hash_base))
|
|
||||||
|| self
|
|| self
|
||||||
.global_sub_modules
|
.global_sub_modules
|
||||||
.values()
|
.values()
|
||||||
@ -420,7 +418,12 @@ impl Engine {
|
|||||||
let context = (self, name, source, &*global, lib, pos, level).into();
|
let context = (self, name, source, &*global, lib, pos, level).into();
|
||||||
|
|
||||||
let result = if func.is_plugin_fn() {
|
let result = if func.is_plugin_fn() {
|
||||||
func.get_plugin_fn().unwrap().call(context, args)
|
let f = func.get_plugin_fn().unwrap();
|
||||||
|
if !f.is_pure() && !args.is_empty() && args[0].is_read_only() {
|
||||||
|
Err(ERR::ErrorNonPureMethodCallOnConstant(name.to_string(), pos).into())
|
||||||
|
} else {
|
||||||
|
f.call(context, args)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
func.get_native_fn().unwrap()(context, args)
|
func.get_native_fn().unwrap()(context, args)
|
||||||
};
|
};
|
||||||
@ -1427,11 +1430,12 @@ impl Engine {
|
|||||||
|
|
||||||
Some(f) if f.is_plugin_fn() => {
|
Some(f) if f.is_plugin_fn() => {
|
||||||
let context = (self, fn_name, module.id(), &*global, lib, pos, level).into();
|
let context = (self, fn_name, module.id(), &*global, lib, pos, level).into();
|
||||||
let result = f
|
let f = f.get_plugin_fn().expect("plugin function");
|
||||||
.get_plugin_fn()
|
let result = if !f.is_pure() && !args.is_empty() && args[0].is_read_only() {
|
||||||
.expect("plugin function")
|
Err(ERR::ErrorNonPureMethodCallOnConstant(fn_name.to_string(), pos).into())
|
||||||
.clone()
|
} else {
|
||||||
.call(context, &mut args);
|
f.call(context, &mut args)
|
||||||
|
};
|
||||||
self.check_return_value(result, pos)
|
self.check_return_value(result, pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,10 +31,10 @@ impl fmt::Debug for CallableFunction {
|
|||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::Pure(..) => write!(f, "NativePureFunction"),
|
Self::Pure(..) => f.write_str("NativePureFunction"),
|
||||||
Self::Method(..) => write!(f, "NativeMethod"),
|
Self::Method(..) => f.write_str("NativeMethod"),
|
||||||
Self::Iterator(..) => write!(f, "NativeIterator"),
|
Self::Iterator(..) => f.write_str("NativeIterator"),
|
||||||
Self::Plugin(..) => write!(f, "PluginFunction"),
|
Self::Plugin(..) => f.write_str("PluginFunction"),
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
Self::Script(fn_def) => fmt::Debug::fmt(fn_def, f),
|
Self::Script(fn_def) => fmt::Debug::fmt(fn_def, f),
|
||||||
@ -45,10 +45,10 @@ impl fmt::Debug for CallableFunction {
|
|||||||
impl fmt::Display for CallableFunction {
|
impl fmt::Display for CallableFunction {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::Pure(..) => write!(f, "NativePureFunction"),
|
Self::Pure(..) => f.write_str("NativePureFunction"),
|
||||||
Self::Method(..) => write!(f, "NativeMethod"),
|
Self::Method(..) => f.write_str("NativeMethod"),
|
||||||
Self::Iterator(..) => write!(f, "NativeIterator"),
|
Self::Iterator(..) => f.write_str("NativeIterator"),
|
||||||
Self::Plugin(..) => write!(f, "PluginFunction"),
|
Self::Plugin(..) => f.write_str("PluginFunction"),
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
Self::Script(s) => fmt::Display::fmt(s, f),
|
Self::Script(s) => fmt::Display::fmt(s, f),
|
||||||
|
@ -81,13 +81,13 @@ pub struct NativeCallContext<'a> {
|
|||||||
level: usize,
|
level: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, M: AsRef<[&'a Module]> + ?Sized, S: AsRef<str> + 'a + ?Sized>
|
impl<'a>
|
||||||
From<(
|
From<(
|
||||||
&'a Engine,
|
&'a Engine,
|
||||||
&'a S,
|
&'a str,
|
||||||
Option<&'a S>,
|
Option<&'a str>,
|
||||||
&'a GlobalRuntimeState<'a>,
|
&'a GlobalRuntimeState<'a>,
|
||||||
&'a M,
|
&'a [&Module],
|
||||||
Position,
|
Position,
|
||||||
usize,
|
usize,
|
||||||
)> for NativeCallContext<'a>
|
)> for NativeCallContext<'a>
|
||||||
@ -96,37 +96,35 @@ impl<'a, M: AsRef<[&'a Module]> + ?Sized, S: AsRef<str> + 'a + ?Sized>
|
|||||||
fn from(
|
fn from(
|
||||||
value: (
|
value: (
|
||||||
&'a Engine,
|
&'a Engine,
|
||||||
&'a S,
|
&'a str,
|
||||||
Option<&'a S>,
|
Option<&'a str>,
|
||||||
&'a GlobalRuntimeState,
|
&'a GlobalRuntimeState,
|
||||||
&'a M,
|
&'a [&Module],
|
||||||
Position,
|
Position,
|
||||||
usize,
|
usize,
|
||||||
),
|
),
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
engine: value.0,
|
engine: value.0,
|
||||||
fn_name: value.1.as_ref(),
|
fn_name: value.1,
|
||||||
source: value.2.map(<_>::as_ref),
|
source: value.2,
|
||||||
global: Some(value.3),
|
global: Some(value.3),
|
||||||
lib: value.4.as_ref(),
|
lib: value.4,
|
||||||
pos: value.5,
|
pos: value.5,
|
||||||
level: value.6,
|
level: value.6,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, M: AsRef<[&'a Module]> + ?Sized, S: AsRef<str> + 'a + ?Sized>
|
impl<'a> From<(&'a Engine, &'a str, &'a [&'a Module])> for NativeCallContext<'a> {
|
||||||
From<(&'a Engine, &'a S, &'a M)> for NativeCallContext<'a>
|
|
||||||
{
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn from(value: (&'a Engine, &'a S, &'a M)) -> Self {
|
fn from(value: (&'a Engine, &'a str, &'a [&Module])) -> Self {
|
||||||
Self {
|
Self {
|
||||||
engine: value.0,
|
engine: value.0,
|
||||||
fn_name: value.1.as_ref(),
|
fn_name: value.1,
|
||||||
source: None,
|
source: None,
|
||||||
global: None,
|
global: None,
|
||||||
lib: value.2.as_ref(),
|
lib: value.2,
|
||||||
pos: Position::NONE,
|
pos: Position::NONE,
|
||||||
level: 0,
|
level: 0,
|
||||||
}
|
}
|
||||||
@ -142,14 +140,10 @@ impl<'a> NativeCallContext<'a> {
|
|||||||
)]
|
)]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(
|
pub fn new(engine: &'a Engine, fn_name: &'a str, lib: &'a [&Module]) -> Self {
|
||||||
engine: &'a Engine,
|
|
||||||
fn_name: &'a (impl AsRef<str> + 'a + ?Sized),
|
|
||||||
lib: &'a [&Module],
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
engine,
|
engine,
|
||||||
fn_name: fn_name.as_ref(),
|
fn_name,
|
||||||
source: None,
|
source: None,
|
||||||
global: None,
|
global: None,
|
||||||
lib,
|
lib,
|
||||||
@ -167,8 +161,8 @@ impl<'a> NativeCallContext<'a> {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new_with_all_fields(
|
pub fn new_with_all_fields(
|
||||||
engine: &'a Engine,
|
engine: &'a Engine,
|
||||||
fn_name: &'a (impl AsRef<str> + 'a + ?Sized),
|
fn_name: &'a str,
|
||||||
source: Option<&'a (impl AsRef<str> + 'a + ?Sized)>,
|
source: Option<&'a str>,
|
||||||
global: &'a GlobalRuntimeState,
|
global: &'a GlobalRuntimeState,
|
||||||
lib: &'a [&Module],
|
lib: &'a [&Module],
|
||||||
pos: Position,
|
pos: Position,
|
||||||
@ -176,8 +170,8 @@ impl<'a> NativeCallContext<'a> {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
engine,
|
engine,
|
||||||
fn_name: fn_name.as_ref(),
|
fn_name,
|
||||||
source: source.map(<_>::as_ref),
|
source,
|
||||||
global: Some(global),
|
global: Some(global),
|
||||||
lib,
|
lib,
|
||||||
pos,
|
pos,
|
||||||
@ -235,7 +229,7 @@ impl<'a> NativeCallContext<'a> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn iter_imports_raw(
|
pub(crate) fn iter_imports_raw(
|
||||||
&self,
|
&self,
|
||||||
) -> impl Iterator<Item = &(crate::ImmutableString, Shared<Module>)> {
|
) -> impl Iterator<Item = (&crate::ImmutableString, &Shared<Module>)> {
|
||||||
self.global.iter().flat_map(|&g| g.iter_imports_raw())
|
self.global.iter().flat_map(|&g| g.iter_imports_raw())
|
||||||
}
|
}
|
||||||
/// _(internals)_ The current [`GlobalRuntimeState`], if any.
|
/// _(internals)_ The current [`GlobalRuntimeState`], if any.
|
||||||
|
@ -29,4 +29,14 @@ pub trait PluginFunction {
|
|||||||
/// Is this plugin function a method?
|
/// Is this plugin function a method?
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn is_method_call(&self) -> bool;
|
fn is_method_call(&self) -> bool;
|
||||||
|
|
||||||
|
/// Is this plugin function pure?
|
||||||
|
///
|
||||||
|
/// This defaults to `true` such that any old implementation that has constant-checking code
|
||||||
|
/// inside the function itself will continue to work.
|
||||||
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
|
fn is_pure(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,26 +96,27 @@ pub trait RegisterNativeFunction<ARGS, RET, RESULT> {
|
|||||||
const EXPECT_ARGS: &str = "arguments";
|
const EXPECT_ARGS: &str = "arguments";
|
||||||
|
|
||||||
macro_rules! check_constant {
|
macro_rules! check_constant {
|
||||||
($ctx:ident, $args:ident) => {
|
($abi:ident, $ctx:ident, $args:ident) => {
|
||||||
#[cfg(any(not(feature = "no_object"), not(feature = "no_index")))]
|
#[cfg(any(not(feature = "no_object"), not(feature = "no_index")))]
|
||||||
{
|
if stringify!($abi) == "Method" && !$args.is_empty() {
|
||||||
let args_len = $args.len();
|
let deny = match $args.len() {
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
if args_len > 0 && $args[0].is_read_only() {
|
3 if $ctx.fn_name() == crate::engine::FN_IDX_SET && $args[0].is_read_only() => true,
|
||||||
let deny = match $ctx.fn_name() {
|
#[cfg(not(feature = "no_object"))]
|
||||||
#[cfg(not(feature = "no_object"))]
|
2 if $ctx.fn_name().starts_with(crate::engine::FN_SET)
|
||||||
f if args_len == 2 && f.starts_with(crate::engine::FN_SET) => true,
|
&& $args[0].is_read_only() =>
|
||||||
#[cfg(not(feature = "no_index"))]
|
{
|
||||||
crate::engine::FN_IDX_SET if args_len == 3 => true,
|
true
|
||||||
_ => false,
|
|
||||||
};
|
|
||||||
if deny {
|
|
||||||
return Err(crate::ERR::ErrorAssignmentToConstant(
|
|
||||||
String::new(),
|
|
||||||
crate::Position::NONE,
|
|
||||||
)
|
|
||||||
.into());
|
|
||||||
}
|
}
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
if deny {
|
||||||
|
return Err(crate::ERR::ErrorNonPureMethodCallOnConstant(
|
||||||
|
$ctx.fn_name().to_string(),
|
||||||
|
crate::Position::NONE,
|
||||||
|
)
|
||||||
|
.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -144,7 +145,7 @@ macro_rules! def_register {
|
|||||||
#[inline(always)] fn into_callable_function(self) -> CallableFunction {
|
#[inline(always)] fn into_callable_function(self) -> CallableFunction {
|
||||||
CallableFunction::$abi(Shared::new(move |_ctx: NativeCallContext, args: &mut FnCallArgs| {
|
CallableFunction::$abi(Shared::new(move |_ctx: NativeCallContext, args: &mut FnCallArgs| {
|
||||||
// The arguments are assumed to be of the correct number and types!
|
// The arguments are assumed to be of the correct number and types!
|
||||||
check_constant!(_ctx, args);
|
check_constant!($abi, _ctx, args);
|
||||||
|
|
||||||
let mut _drain = args.iter_mut();
|
let mut _drain = args.iter_mut();
|
||||||
$($let $par = ($clone)(_drain.next().expect(EXPECT_ARGS)); )*
|
$($let $par = ($clone)(_drain.next().expect(EXPECT_ARGS)); )*
|
||||||
@ -169,7 +170,7 @@ macro_rules! def_register {
|
|||||||
#[inline(always)] fn into_callable_function(self) -> CallableFunction {
|
#[inline(always)] fn into_callable_function(self) -> CallableFunction {
|
||||||
CallableFunction::$abi(Shared::new(move |ctx: NativeCallContext, args: &mut FnCallArgs| {
|
CallableFunction::$abi(Shared::new(move |ctx: NativeCallContext, args: &mut FnCallArgs| {
|
||||||
// The arguments are assumed to be of the correct number and types!
|
// The arguments are assumed to be of the correct number and types!
|
||||||
check_constant!(ctx, args);
|
check_constant!($abi, ctx, args);
|
||||||
|
|
||||||
let mut _drain = args.iter_mut();
|
let mut _drain = args.iter_mut();
|
||||||
$($let $par = ($clone)(_drain.next().expect(EXPECT_ARGS)); )*
|
$($let $par = ($clone)(_drain.next().expect(EXPECT_ARGS)); )*
|
||||||
@ -195,7 +196,7 @@ macro_rules! def_register {
|
|||||||
#[inline(always)] fn into_callable_function(self) -> CallableFunction {
|
#[inline(always)] fn into_callable_function(self) -> CallableFunction {
|
||||||
CallableFunction::$abi(Shared::new(move |_ctx: NativeCallContext, args: &mut FnCallArgs| {
|
CallableFunction::$abi(Shared::new(move |_ctx: NativeCallContext, args: &mut FnCallArgs| {
|
||||||
// The arguments are assumed to be of the correct number and types!
|
// The arguments are assumed to be of the correct number and types!
|
||||||
check_constant!(_ctx, args);
|
check_constant!($abi, _ctx, args);
|
||||||
|
|
||||||
let mut _drain = args.iter_mut();
|
let mut _drain = args.iter_mut();
|
||||||
$($let $par = ($clone)(_drain.next().expect(EXPECT_ARGS)); )*
|
$($let $par = ($clone)(_drain.next().expect(EXPECT_ARGS)); )*
|
||||||
@ -218,7 +219,7 @@ macro_rules! def_register {
|
|||||||
#[inline(always)] fn into_callable_function(self) -> CallableFunction {
|
#[inline(always)] fn into_callable_function(self) -> CallableFunction {
|
||||||
CallableFunction::$abi(Shared::new(move |ctx: NativeCallContext, args: &mut FnCallArgs| {
|
CallableFunction::$abi(Shared::new(move |ctx: NativeCallContext, args: &mut FnCallArgs| {
|
||||||
// The arguments are assumed to be of the correct number and types!
|
// The arguments are assumed to be of the correct number and types!
|
||||||
check_constant!(ctx, args);
|
check_constant!($abi, ctx, args);
|
||||||
|
|
||||||
let mut _drain = args.iter_mut();
|
let mut _drain = args.iter_mut();
|
||||||
$($let $par = ($clone)(_drain.next().expect(EXPECT_ARGS)); )*
|
$($let $par = ($clone)(_drain.next().expect(EXPECT_ARGS)); )*
|
||||||
|
@ -204,7 +204,6 @@ pub use eval::EvalContext;
|
|||||||
pub use func::{NativeCallContext, RegisterNativeFunction};
|
pub use func::{NativeCallContext, RegisterNativeFunction};
|
||||||
pub use module::{FnNamespace, Module};
|
pub use module::{FnNamespace, Module};
|
||||||
pub use tokenizer::Position;
|
pub use tokenizer::Position;
|
||||||
#[cfg(not(feature = "no_std"))]
|
|
||||||
#[cfg(not(feature = "no_time"))]
|
#[cfg(not(feature = "no_time"))]
|
||||||
pub use types::Instant;
|
pub use types::Instant;
|
||||||
pub use types::{
|
pub use types::{
|
||||||
|
@ -175,21 +175,26 @@ fn has_native_fn_override(
|
|||||||
|
|
||||||
// First check the global namespace and packages, but skip modules that are standard because
|
// First check the global namespace and packages, but skip modules that are standard because
|
||||||
// they should never conflict with system functions.
|
// they should never conflict with system functions.
|
||||||
let result = engine
|
if engine
|
||||||
.global_modules
|
.global_modules
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|m| !m.standard)
|
.filter(|m| !m.standard)
|
||||||
.any(|m| m.contains_fn(hash));
|
.any(|m| m.contains_fn(hash))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
|
||||||
// Then check sub-modules
|
// Then check sub-modules
|
||||||
let result = result
|
#[cfg(not(feature = "no_module"))]
|
||||||
|| engine
|
if engine
|
||||||
.global_sub_modules
|
.global_sub_modules
|
||||||
.values()
|
.values()
|
||||||
.any(|m| m.contains_qualified_fn(hash));
|
.any(|m| m.contains_qualified_fn(hash))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
result
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Optimize a block of [statements][Stmt].
|
/// Optimize a block of [statements][Stmt].
|
||||||
@ -1184,9 +1189,9 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, _chaining: bool) {
|
|||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
let lib = state.lib;
|
let lib = state.lib;
|
||||||
#[cfg(feature = "no_function")]
|
#[cfg(feature = "no_function")]
|
||||||
let lib = &[];
|
let lib = &[][..];
|
||||||
|
|
||||||
let context = (state.engine, &x.name, lib).into();
|
let context = (state.engine, x.name.as_str(), lib).into();
|
||||||
let (first, second) = arg_values.split_first_mut().unwrap();
|
let (first, second) = arg_values.split_first_mut().unwrap();
|
||||||
(f)(context, &mut [ first, &mut second[0] ]).ok()
|
(f)(context, &mut [ first, &mut second[0] ]).ok()
|
||||||
}) {
|
}) {
|
||||||
|
@ -259,7 +259,7 @@ pub mod array_functions {
|
|||||||
s1 += s2;
|
s1 += s2;
|
||||||
|
|
||||||
_ctx.engine()
|
_ctx.engine()
|
||||||
.raise_err_if_over_data_size_limit((a1, m1, s1), Position::NONE)?;
|
.raise_err_if_over_data_size_limit((a1, m1, s1))?;
|
||||||
|
|
||||||
guard.push(item.clone());
|
guard.push(item.clone());
|
||||||
arr_len += 1;
|
arr_len += 1;
|
||||||
|
@ -79,11 +79,9 @@ pub mod blob_functions {
|
|||||||
let _ctx = ctx;
|
let _ctx = ctx;
|
||||||
|
|
||||||
// Check if blob will be over max size limit
|
// Check if blob will be over max size limit
|
||||||
if _ctx.engine().max_array_size() > 0 && len > _ctx.engine().max_array_size() {
|
#[cfg(not(feature = "unchecked"))]
|
||||||
return Err(
|
_ctx.engine()
|
||||||
crate::ERR::ErrorDataTooLarge("Size of BLOB".to_string(), Position::NONE).into(),
|
.raise_err_if_over_data_size_limit((len, 0, 0))?;
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut blob = Blob::new();
|
let mut blob = Blob::new();
|
||||||
blob.resize(len, (value & 0x0000_00ff) as u8);
|
blob.resize(len, (value & 0x0000_00ff) as u8);
|
||||||
|
@ -38,7 +38,6 @@ pub use pkg_core::CorePackage;
|
|||||||
pub use pkg_std::StandardPackage;
|
pub use pkg_std::StandardPackage;
|
||||||
pub use string_basic::BasicStringPackage;
|
pub use string_basic::BasicStringPackage;
|
||||||
pub use string_more::MoreStringPackage;
|
pub use string_more::MoreStringPackage;
|
||||||
#[cfg(not(feature = "no_std"))]
|
|
||||||
#[cfg(not(feature = "no_time"))]
|
#[cfg(not(feature = "no_time"))]
|
||||||
pub use time_basic::BasicTimePackage;
|
pub use time_basic::BasicTimePackage;
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ def_package! {
|
|||||||
#[cfg(not(feature = "no_index"))] BasicArrayPackage,
|
#[cfg(not(feature = "no_index"))] BasicArrayPackage,
|
||||||
#[cfg(not(feature = "no_index"))] BasicBlobPackage,
|
#[cfg(not(feature = "no_index"))] BasicBlobPackage,
|
||||||
#[cfg(not(feature = "no_object"))] BasicMapPackage,
|
#[cfg(not(feature = "no_object"))] BasicMapPackage,
|
||||||
#[cfg(all(not(feature = "no_std"), not(feature = "no_time")))] BasicTimePackage,
|
#[cfg(not(feature = "no_time"))] BasicTimePackage,
|
||||||
MoreStringPackage
|
MoreStringPackage
|
||||||
{
|
{
|
||||||
lib.standard = true;
|
lib.standard = true;
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
#![cfg(not(feature = "no_std"))]
|
|
||||||
#![cfg(not(feature = "no_time"))]
|
#![cfg(not(feature = "no_time"))]
|
||||||
|
|
||||||
use super::arithmetic::make_err as make_arithmetic_err;
|
use super::arithmetic::make_err as make_arithmetic_err;
|
||||||
|
@ -1441,7 +1441,7 @@ impl Engine {
|
|||||||
..settings
|
..settings
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = self.parse_anon_fn(input, &mut new_state, lib, new_settings);
|
let result = self.parse_anon_fn(input, &mut new_state, state, lib, new_settings);
|
||||||
|
|
||||||
// Restore parse state
|
// Restore parse state
|
||||||
state.interned_strings = new_state.interned_strings;
|
state.interned_strings = new_state.interned_strings;
|
||||||
@ -1464,7 +1464,7 @@ impl Engine {
|
|||||||
// Under Strict Variables mode, this is not allowed.
|
// Under Strict Variables mode, this is not allowed.
|
||||||
Err(PERR::VariableUndefined(name.to_string()).into_err(*pos))
|
Err(PERR::VariableUndefined(name.to_string()).into_err(*pos))
|
||||||
} else {
|
} else {
|
||||||
Ok::<_, ParseError>(())
|
Ok(())
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
@ -3655,6 +3655,8 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
fn make_curry_from_externals(
|
fn make_curry_from_externals(
|
||||||
state: &mut ParseState,
|
state: &mut ParseState,
|
||||||
|
parent: &mut ParseState,
|
||||||
|
lib: &FnLib,
|
||||||
fn_expr: Expr,
|
fn_expr: Expr,
|
||||||
externals: StaticVec<crate::ast::Ident>,
|
externals: StaticVec<crate::ast::Ident>,
|
||||||
pos: Position,
|
pos: Position,
|
||||||
@ -3674,12 +3676,14 @@ impl Engine {
|
|||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
.map(|crate::ast::Ident { name, pos }| {
|
.map(|crate::ast::Ident { name, pos }| {
|
||||||
#[cfg(not(feature = "no_module"))]
|
let (index, is_func) = parent.access_var(&name, lib, pos);
|
||||||
let ns = crate::ast::Namespace::NONE;
|
let idx = match index {
|
||||||
#[cfg(feature = "no_module")]
|
Some(n) if !is_func && n.get() <= u8::MAX as usize => {
|
||||||
let ns = ();
|
NonZeroU8::new(n.get() as u8)
|
||||||
|
}
|
||||||
Expr::Variable((None, ns, 0, name).into(), None, pos)
|
_ => None,
|
||||||
|
};
|
||||||
|
Expr::Variable((index, Default::default(), 0, name).into(), idx, pos)
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -3707,7 +3711,10 @@ impl Engine {
|
|||||||
statements.extend(
|
statements.extend(
|
||||||
externals
|
externals
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|crate::ast::Ident { name, pos }| Stmt::Share(name, pos)),
|
.map(|crate::ast::Ident { name, pos }| {
|
||||||
|
let (index, _) = parent.access_var(&name, lib, pos);
|
||||||
|
Stmt::Share((name, index).into(), pos)
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
statements.push(Stmt::Expr(expr.into()));
|
statements.push(Stmt::Expr(expr.into()));
|
||||||
Expr::Stmt(crate::ast::StmtBlock::new(statements, pos, Position::NONE).into())
|
Expr::Stmt(crate::ast::StmtBlock::new(statements, pos, Position::NONE).into())
|
||||||
@ -3719,6 +3726,7 @@ impl Engine {
|
|||||||
&self,
|
&self,
|
||||||
input: &mut TokenStream,
|
input: &mut TokenStream,
|
||||||
state: &mut ParseState,
|
state: &mut ParseState,
|
||||||
|
parent: &mut ParseState,
|
||||||
lib: &mut FnLib,
|
lib: &mut FnLib,
|
||||||
settings: ParseSettings,
|
settings: ParseSettings,
|
||||||
) -> ParseResult<(Expr, ScriptFnDef)> {
|
) -> ParseResult<(Expr, ScriptFnDef)> {
|
||||||
@ -3815,7 +3823,8 @@ impl Engine {
|
|||||||
let expr = Expr::DynamicConstant(Box::new(fn_ptr.into()), settings.pos);
|
let expr = Expr::DynamicConstant(Box::new(fn_ptr.into()), settings.pos);
|
||||||
|
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
let expr = Self::make_curry_from_externals(state, expr, externals, settings.pos);
|
let expr =
|
||||||
|
Self::make_curry_from_externals(state, parent, lib, expr, externals, settings.pos);
|
||||||
|
|
||||||
Ok((expr, script))
|
Ok((expr, script))
|
||||||
}
|
}
|
||||||
|
@ -156,7 +156,6 @@ impl<'de> Deserializer<'de> for DynamicDeserializer<'de> {
|
|||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Union::Map(..) => self.deserialize_map(visitor),
|
Union::Map(..) => self.deserialize_map(visitor),
|
||||||
Union::FnPtr(..) => self.type_error(),
|
Union::FnPtr(..) => self.type_error(),
|
||||||
#[cfg(not(feature = "no_std"))]
|
|
||||||
#[cfg(not(feature = "no_time"))]
|
#[cfg(not(feature = "no_time"))]
|
||||||
Union::TimeStamp(..) => self.type_error(),
|
Union::TimeStamp(..) => self.type_error(),
|
||||||
|
|
||||||
|
@ -9,7 +9,6 @@ use std::prelude::v1::*;
|
|||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
use serde::ser::SerializeMap;
|
use serde::ser::SerializeMap;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_std"))]
|
|
||||||
#[cfg(not(feature = "no_time"))]
|
#[cfg(not(feature = "no_time"))]
|
||||||
use crate::types::dynamic::Variant;
|
use crate::types::dynamic::Variant;
|
||||||
|
|
||||||
@ -66,7 +65,6 @@ impl Serialize for Dynamic {
|
|||||||
map.end()
|
map.end()
|
||||||
}
|
}
|
||||||
Union::FnPtr(ref f, ..) => ser.serialize_str(f.fn_name()),
|
Union::FnPtr(ref f, ..) => ser.serialize_str(f.fn_name()),
|
||||||
#[cfg(not(feature = "no_std"))]
|
|
||||||
#[cfg(not(feature = "no_time"))]
|
#[cfg(not(feature = "no_time"))]
|
||||||
Union::TimeStamp(ref x, ..) => ser.serialize_str(x.as_ref().type_name()),
|
Union::TimeStamp(ref x, ..) => ser.serialize_str(x.as_ref().type_name()),
|
||||||
|
|
||||||
|
@ -14,12 +14,10 @@ use std::{
|
|||||||
|
|
||||||
pub use super::Variant;
|
pub use super::Variant;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_std"))]
|
|
||||||
#[cfg(not(feature = "no_time"))]
|
#[cfg(not(feature = "no_time"))]
|
||||||
#[cfg(not(target_family = "wasm"))]
|
#[cfg(not(target_family = "wasm"))]
|
||||||
pub use std::time::Instant;
|
pub use std::time::Instant;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_std"))]
|
|
||||||
#[cfg(not(feature = "no_time"))]
|
#[cfg(not(feature = "no_time"))]
|
||||||
#[cfg(target_family = "wasm")]
|
#[cfg(target_family = "wasm")]
|
||||||
pub use instant::Instant;
|
pub use instant::Instant;
|
||||||
@ -86,7 +84,6 @@ pub enum Union {
|
|||||||
/// A function pointer.
|
/// A function pointer.
|
||||||
FnPtr(Box<FnPtr>, Tag, AccessMode),
|
FnPtr(Box<FnPtr>, Tag, AccessMode),
|
||||||
/// A timestamp value.
|
/// A timestamp value.
|
||||||
#[cfg(not(feature = "no_std"))]
|
|
||||||
#[cfg(not(feature = "no_time"))]
|
#[cfg(not(feature = "no_time"))]
|
||||||
TimeStamp(Box<Instant>, Tag, AccessMode),
|
TimeStamp(Box<Instant>, Tag, AccessMode),
|
||||||
|
|
||||||
@ -197,7 +194,6 @@ impl Dynamic {
|
|||||||
Union::Array(_, tag, _) | Union::Blob(_, tag, _) => tag,
|
Union::Array(_, tag, _) | Union::Blob(_, tag, _) => tag,
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Union::Map(_, tag, _) => tag,
|
Union::Map(_, tag, _) => tag,
|
||||||
#[cfg(not(feature = "no_std"))]
|
|
||||||
#[cfg(not(feature = "no_time"))]
|
#[cfg(not(feature = "no_time"))]
|
||||||
Union::TimeStamp(_, tag, _) => tag,
|
Union::TimeStamp(_, tag, _) => tag,
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
@ -223,7 +219,6 @@ impl Dynamic {
|
|||||||
Union::Array(_, ref mut tag, _) | Union::Blob(_, ref mut tag, _) => *tag = value,
|
Union::Array(_, ref mut tag, _) | Union::Blob(_, ref mut tag, _) => *tag = value,
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Union::Map(_, ref mut tag, _) => *tag = value,
|
Union::Map(_, ref mut tag, _) => *tag = value,
|
||||||
#[cfg(not(feature = "no_std"))]
|
|
||||||
#[cfg(not(feature = "no_time"))]
|
#[cfg(not(feature = "no_time"))]
|
||||||
Union::TimeStamp(_, ref mut tag, _) => *tag = value,
|
Union::TimeStamp(_, ref mut tag, _) => *tag = value,
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
@ -296,7 +291,6 @@ impl Dynamic {
|
|||||||
if TypeId::of::<T>() == TypeId::of::<FnPtr>() {
|
if TypeId::of::<T>() == TypeId::of::<FnPtr>() {
|
||||||
return matches!(self.0, Union::FnPtr(..));
|
return matches!(self.0, Union::FnPtr(..));
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "no_std"))]
|
|
||||||
#[cfg(not(feature = "no_time"))]
|
#[cfg(not(feature = "no_time"))]
|
||||||
if TypeId::of::<T>() == TypeId::of::<crate::Instant>() {
|
if TypeId::of::<T>() == TypeId::of::<crate::Instant>() {
|
||||||
return matches!(self.0, Union::TimeStamp(..));
|
return matches!(self.0, Union::TimeStamp(..));
|
||||||
@ -329,7 +323,6 @@ impl Dynamic {
|
|||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Union::Map(..) => TypeId::of::<crate::Map>(),
|
Union::Map(..) => TypeId::of::<crate::Map>(),
|
||||||
Union::FnPtr(..) => TypeId::of::<FnPtr>(),
|
Union::FnPtr(..) => TypeId::of::<FnPtr>(),
|
||||||
#[cfg(not(feature = "no_std"))]
|
|
||||||
#[cfg(not(feature = "no_time"))]
|
#[cfg(not(feature = "no_time"))]
|
||||||
Union::TimeStamp(..) => TypeId::of::<Instant>(),
|
Union::TimeStamp(..) => TypeId::of::<Instant>(),
|
||||||
|
|
||||||
@ -364,7 +357,6 @@ impl Dynamic {
|
|||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Union::Map(..) => "map",
|
Union::Map(..) => "map",
|
||||||
Union::FnPtr(..) => "Fn",
|
Union::FnPtr(..) => "Fn",
|
||||||
#[cfg(not(feature = "no_std"))]
|
|
||||||
#[cfg(not(feature = "no_time"))]
|
#[cfg(not(feature = "no_time"))]
|
||||||
Union::TimeStamp(..) => "timestamp",
|
Union::TimeStamp(..) => "timestamp",
|
||||||
|
|
||||||
@ -415,7 +407,6 @@ impl Hash for Dynamic {
|
|||||||
|
|
||||||
Union::Variant(..) => unimplemented!("{} cannot be hashed", self.type_name()),
|
Union::Variant(..) => unimplemented!("{} cannot be hashed", self.type_name()),
|
||||||
|
|
||||||
#[cfg(not(feature = "no_std"))]
|
|
||||||
#[cfg(not(feature = "no_time"))]
|
#[cfg(not(feature = "no_time"))]
|
||||||
Union::TimeStamp(..) => unimplemented!("{} cannot be hashed", self.type_name()),
|
Union::TimeStamp(..) => unimplemented!("{} cannot be hashed", self.type_name()),
|
||||||
}
|
}
|
||||||
@ -425,7 +416,7 @@ impl Hash for Dynamic {
|
|||||||
impl fmt::Display for Dynamic {
|
impl fmt::Display for Dynamic {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self.0 {
|
match self.0 {
|
||||||
Union::Unit(..) => write!(f, ""),
|
Union::Unit(..) => Ok(()),
|
||||||
Union::Bool(ref v, ..) => fmt::Display::fmt(v, f),
|
Union::Bool(ref v, ..) => fmt::Display::fmt(v, f),
|
||||||
Union::Str(ref v, ..) => fmt::Display::fmt(v, f),
|
Union::Str(ref v, ..) => fmt::Display::fmt(v, f),
|
||||||
Union::Char(ref v, ..) => fmt::Display::fmt(v, f),
|
Union::Char(ref v, ..) => fmt::Display::fmt(v, f),
|
||||||
@ -441,7 +432,6 @@ impl fmt::Display for Dynamic {
|
|||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Union::Map(..) => fmt::Debug::fmt(self, f),
|
Union::Map(..) => fmt::Debug::fmt(self, f),
|
||||||
Union::FnPtr(ref v, ..) => fmt::Display::fmt(v, f),
|
Union::FnPtr(ref v, ..) => fmt::Display::fmt(v, f),
|
||||||
#[cfg(not(feature = "no_std"))]
|
|
||||||
#[cfg(not(feature = "no_time"))]
|
#[cfg(not(feature = "no_time"))]
|
||||||
Union::TimeStamp(..) => f.write_str("<timestamp>"),
|
Union::TimeStamp(..) => f.write_str("<timestamp>"),
|
||||||
|
|
||||||
@ -537,7 +527,7 @@ impl fmt::Debug for Dynamic {
|
|||||||
if i > 0 && i % 8 == 0 {
|
if i > 0 && i % 8 == 0 {
|
||||||
f.write_str(" ")?;
|
f.write_str(" ")?;
|
||||||
}
|
}
|
||||||
write!(f, "{:02x}", v)
|
write!(f, "{v:02x}")
|
||||||
})?;
|
})?;
|
||||||
f.write_str("]")
|
f.write_str("]")
|
||||||
}
|
}
|
||||||
@ -547,7 +537,6 @@ impl fmt::Debug for Dynamic {
|
|||||||
fmt::Debug::fmt(v, f)
|
fmt::Debug::fmt(v, f)
|
||||||
}
|
}
|
||||||
Union::FnPtr(ref v, ..) => fmt::Debug::fmt(v, f),
|
Union::FnPtr(ref v, ..) => fmt::Debug::fmt(v, f),
|
||||||
#[cfg(not(feature = "no_std"))]
|
|
||||||
#[cfg(not(feature = "no_time"))]
|
#[cfg(not(feature = "no_time"))]
|
||||||
Union::TimeStamp(..) => write!(f, "<timestamp>"),
|
Union::TimeStamp(..) => write!(f, "<timestamp>"),
|
||||||
|
|
||||||
@ -646,7 +635,6 @@ impl Clone for Dynamic {
|
|||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Union::Map(ref v, tag, ..) => Self(Union::Map(v.clone(), tag, ReadWrite)),
|
Union::Map(ref v, tag, ..) => Self(Union::Map(v.clone(), tag, ReadWrite)),
|
||||||
Union::FnPtr(ref v, tag, ..) => Self(Union::FnPtr(v.clone(), tag, ReadWrite)),
|
Union::FnPtr(ref v, tag, ..) => Self(Union::FnPtr(v.clone(), tag, ReadWrite)),
|
||||||
#[cfg(not(feature = "no_std"))]
|
|
||||||
#[cfg(not(feature = "no_time"))]
|
#[cfg(not(feature = "no_time"))]
|
||||||
Union::TimeStamp(ref v, tag, ..) => Self(Union::TimeStamp(v.clone(), tag, ReadWrite)),
|
Union::TimeStamp(ref v, tag, ..) => Self(Union::TimeStamp(v.clone(), tag, ReadWrite)),
|
||||||
|
|
||||||
@ -889,7 +877,6 @@ impl Dynamic {
|
|||||||
/// Create a new [`Dynamic`] from an [`Instant`].
|
/// Create a new [`Dynamic`] from an [`Instant`].
|
||||||
///
|
///
|
||||||
/// Not available under `no-std` or `no_time`.
|
/// Not available under `no-std` or `no_time`.
|
||||||
#[cfg(not(feature = "no_std"))]
|
|
||||||
#[cfg(not(feature = "no_time"))]
|
#[cfg(not(feature = "no_time"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
@ -917,7 +904,6 @@ impl Dynamic {
|
|||||||
Union::Array(.., access) | Union::Blob(.., access) => access,
|
Union::Array(.., access) | Union::Blob(.., access) => access,
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Union::Map(.., access) => access,
|
Union::Map(.., access) => access,
|
||||||
#[cfg(not(feature = "no_std"))]
|
|
||||||
#[cfg(not(feature = "no_time"))]
|
#[cfg(not(feature = "no_time"))]
|
||||||
Union::TimeStamp(.., access) => access,
|
Union::TimeStamp(.., access) => access,
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
@ -955,7 +941,6 @@ impl Dynamic {
|
|||||||
v.set_access_mode(typ);
|
v.set_access_mode(typ);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "no_std"))]
|
|
||||||
#[cfg(not(feature = "no_time"))]
|
#[cfg(not(feature = "no_time"))]
|
||||||
Union::TimeStamp(.., ref mut access) => *access = typ,
|
Union::TimeStamp(.., ref mut access) => *access = typ,
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
@ -1090,7 +1075,6 @@ impl Dynamic {
|
|||||||
reify!(value, |v: crate::Map| return v.into());
|
reify!(value, |v: crate::Map| return v.into());
|
||||||
reify!(value, |v: FnPtr| return v.into());
|
reify!(value, |v: FnPtr| return v.into());
|
||||||
|
|
||||||
#[cfg(not(feature = "no_std"))]
|
|
||||||
#[cfg(not(feature = "no_time"))]
|
#[cfg(not(feature = "no_time"))]
|
||||||
reify!(value, |v: Instant| return v.into());
|
reify!(value, |v: Instant| return v.into());
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
@ -1184,7 +1168,6 @@ impl Dynamic {
|
|||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Union::Map(v, ..) => reify!(*v => Option<T>),
|
Union::Map(v, ..) => reify!(*v => Option<T>),
|
||||||
Union::FnPtr(v, ..) => reify!(*v => Option<T>),
|
Union::FnPtr(v, ..) => reify!(*v => Option<T>),
|
||||||
#[cfg(not(feature = "no_std"))]
|
|
||||||
#[cfg(not(feature = "no_time"))]
|
#[cfg(not(feature = "no_time"))]
|
||||||
Union::TimeStamp(v, ..) => reify!(*v => Option<T>),
|
Union::TimeStamp(v, ..) => reify!(*v => Option<T>),
|
||||||
Union::Unit(v, ..) => reify!(v => Option<T>),
|
Union::Unit(v, ..) => reify!(v => Option<T>),
|
||||||
@ -1484,7 +1467,6 @@ impl Dynamic {
|
|||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "no_std"))]
|
|
||||||
#[cfg(not(feature = "no_time"))]
|
#[cfg(not(feature = "no_time"))]
|
||||||
if TypeId::of::<T>() == TypeId::of::<Instant>() {
|
if TypeId::of::<T>() == TypeId::of::<Instant>() {
|
||||||
return match self.0 {
|
return match self.0 {
|
||||||
@ -1583,7 +1565,6 @@ impl Dynamic {
|
|||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "no_std"))]
|
|
||||||
#[cfg(not(feature = "no_time"))]
|
#[cfg(not(feature = "no_time"))]
|
||||||
if TypeId::of::<T>() == TypeId::of::<Instant>() {
|
if TypeId::of::<T>() == TypeId::of::<Instant>() {
|
||||||
return match self.0 {
|
return match self.0 {
|
||||||
@ -1978,7 +1959,6 @@ impl From<FnPtr> for Dynamic {
|
|||||||
Self(Union::FnPtr(value.into(), DEFAULT_TAG_VALUE, ReadWrite))
|
Self(Union::FnPtr(value.into(), DEFAULT_TAG_VALUE, ReadWrite))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "no_std"))]
|
|
||||||
#[cfg(not(feature = "no_time"))]
|
#[cfg(not(feature = "no_time"))]
|
||||||
impl From<Instant> for Dynamic {
|
impl From<Instant> for Dynamic {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -84,6 +84,8 @@ pub enum EvalAltResult {
|
|||||||
|
|
||||||
/// Data race detected when accessing a variable. Wrapped value is the variable name.
|
/// Data race detected when accessing a variable. Wrapped value is the variable name.
|
||||||
ErrorDataRace(String, Position),
|
ErrorDataRace(String, Position),
|
||||||
|
/// Calling a non-pure method on a constant. Wrapped value is the function name.
|
||||||
|
ErrorNonPureMethodCallOnConstant(String, Position),
|
||||||
/// Assignment to a constant variable. Wrapped value is the variable name.
|
/// Assignment to a constant variable. Wrapped value is the variable name.
|
||||||
ErrorAssignmentToConstant(String, Position),
|
ErrorAssignmentToConstant(String, Position),
|
||||||
/// Inappropriate property access. Wrapped value is the property name.
|
/// Inappropriate property access. Wrapped value is the property name.
|
||||||
@ -181,7 +183,39 @@ impl fmt::Display for EvalAltResult {
|
|||||||
}
|
}
|
||||||
Self::ErrorRuntime(d, ..) => write!(f, "Runtime error: {d}")?,
|
Self::ErrorRuntime(d, ..) => write!(f, "Runtime error: {d}")?,
|
||||||
|
|
||||||
Self::ErrorAssignmentToConstant(s, ..) => write!(f, "Cannot modify constant: {s}")?,
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
Self::ErrorNonPureMethodCallOnConstant(s, ..)
|
||||||
|
if s.starts_with(crate::engine::FN_GET) =>
|
||||||
|
{
|
||||||
|
let prop = &s[crate::engine::FN_GET.len()..];
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"Property {prop} is not pure and cannot be accessed on a constant"
|
||||||
|
)?
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
Self::ErrorNonPureMethodCallOnConstant(s, ..)
|
||||||
|
if s.starts_with(crate::engine::FN_SET) =>
|
||||||
|
{
|
||||||
|
let prop = &s[crate::engine::FN_SET.len()..];
|
||||||
|
write!(f, "Cannot modify property {prop} of constant")?
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
Self::ErrorNonPureMethodCallOnConstant(s, ..) if s == crate::engine::FN_IDX_GET => {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"Indexer is not pure and cannot be accessed on a constant"
|
||||||
|
)?
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
Self::ErrorNonPureMethodCallOnConstant(s, ..) if s == crate::engine::FN_IDX_SET => {
|
||||||
|
write!(f, "Cannot assign to indexer of constant")?
|
||||||
|
}
|
||||||
|
Self::ErrorNonPureMethodCallOnConstant(s, ..) => {
|
||||||
|
write!(f, "Non-pure method {s} cannot be called on constant")?
|
||||||
|
}
|
||||||
|
|
||||||
|
Self::ErrorAssignmentToConstant(s, ..) => write!(f, "Cannot modify constant {s}")?,
|
||||||
Self::ErrorMismatchOutputType(e, a, ..) => match (a.as_str(), e.as_str()) {
|
Self::ErrorMismatchOutputType(e, a, ..) => match (a.as_str(), e.as_str()) {
|
||||||
("", e) => write!(f, "Output type incorrect, expecting {e}"),
|
("", e) => write!(f, "Output type incorrect, expecting {e}"),
|
||||||
(a, "") => write!(f, "Output type incorrect: {a}"),
|
(a, "") => write!(f, "Output type incorrect: {a}"),
|
||||||
@ -296,6 +330,7 @@ impl EvalAltResult {
|
|||||||
| Self::ErrorIndexNotFound(..)
|
| Self::ErrorIndexNotFound(..)
|
||||||
| Self::ErrorModuleNotFound(..)
|
| Self::ErrorModuleNotFound(..)
|
||||||
| Self::ErrorDataRace(..)
|
| Self::ErrorDataRace(..)
|
||||||
|
| Self::ErrorNonPureMethodCallOnConstant(..)
|
||||||
| Self::ErrorAssignmentToConstant(..)
|
| Self::ErrorAssignmentToConstant(..)
|
||||||
| Self::ErrorMismatchOutputType(..)
|
| Self::ErrorMismatchOutputType(..)
|
||||||
| Self::ErrorDotExpr(..)
|
| Self::ErrorDotExpr(..)
|
||||||
@ -364,7 +399,7 @@ impl EvalAltResult {
|
|||||||
| Self::ErrorStackOverflow(..)
|
| Self::ErrorStackOverflow(..)
|
||||||
| Self::ErrorRuntime(..) => (),
|
| Self::ErrorRuntime(..) => (),
|
||||||
|
|
||||||
Self::ErrorFunctionNotFound(f, ..) => {
|
Self::ErrorFunctionNotFound(f, ..) | Self::ErrorNonPureMethodCallOnConstant(f, ..) => {
|
||||||
map.insert("function".into(), f.into());
|
map.insert("function".into(), f.into());
|
||||||
}
|
}
|
||||||
Self::ErrorInFunctionCall(f, s, ..) => {
|
Self::ErrorInFunctionCall(f, s, ..) => {
|
||||||
@ -459,6 +494,7 @@ impl EvalAltResult {
|
|||||||
| Self::ErrorIndexNotFound(.., pos)
|
| Self::ErrorIndexNotFound(.., pos)
|
||||||
| Self::ErrorModuleNotFound(.., pos)
|
| Self::ErrorModuleNotFound(.., pos)
|
||||||
| Self::ErrorDataRace(.., pos)
|
| Self::ErrorDataRace(.., pos)
|
||||||
|
| Self::ErrorNonPureMethodCallOnConstant(.., pos)
|
||||||
| Self::ErrorAssignmentToConstant(.., pos)
|
| Self::ErrorAssignmentToConstant(.., pos)
|
||||||
| Self::ErrorMismatchOutputType(.., pos)
|
| Self::ErrorMismatchOutputType(.., pos)
|
||||||
| Self::ErrorDotExpr(.., pos)
|
| Self::ErrorDotExpr(.., pos)
|
||||||
@ -518,6 +554,7 @@ impl EvalAltResult {
|
|||||||
| Self::ErrorIndexNotFound(.., pos)
|
| Self::ErrorIndexNotFound(.., pos)
|
||||||
| Self::ErrorModuleNotFound(.., pos)
|
| Self::ErrorModuleNotFound(.., pos)
|
||||||
| Self::ErrorDataRace(.., pos)
|
| Self::ErrorDataRace(.., pos)
|
||||||
|
| Self::ErrorNonPureMethodCallOnConstant(.., pos)
|
||||||
| Self::ErrorAssignmentToConstant(.., pos)
|
| Self::ErrorAssignmentToConstant(.., pos)
|
||||||
| Self::ErrorMismatchOutputType(.., pos)
|
| Self::ErrorMismatchOutputType(.., pos)
|
||||||
| Self::ErrorDotExpr(.., pos)
|
| Self::ErrorDotExpr(.., pos)
|
||||||
|
@ -14,7 +14,6 @@ pub mod variant;
|
|||||||
pub use bloom_filter::BloomFilterU64;
|
pub use bloom_filter::BloomFilterU64;
|
||||||
pub use custom_types::{CustomTypeInfo, CustomTypesCollection};
|
pub use custom_types::{CustomTypeInfo, CustomTypesCollection};
|
||||||
pub use dynamic::Dynamic;
|
pub use dynamic::Dynamic;
|
||||||
#[cfg(not(feature = "no_std"))]
|
|
||||||
#[cfg(not(feature = "no_time"))]
|
#[cfg(not(feature = "no_time"))]
|
||||||
pub use dynamic::Instant;
|
pub use dynamic::Instant;
|
||||||
pub use error::EvalAltResult;
|
pub use error::EvalAltResult;
|
||||||
|
@ -38,11 +38,11 @@ impl Error for LexError {}
|
|||||||
impl fmt::Display for LexError {
|
impl fmt::Display for LexError {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::UnexpectedInput(s) => write!(f, "Unexpected '{}'", s),
|
Self::UnexpectedInput(s) => write!(f, "Unexpected '{s}'"),
|
||||||
Self::MalformedEscapeSequence(s) => write!(f, "Invalid escape sequence: '{}'", s),
|
Self::MalformedEscapeSequence(s) => write!(f, "Invalid escape sequence: '{s}'"),
|
||||||
Self::MalformedNumber(s) => write!(f, "Invalid number: '{}'", s),
|
Self::MalformedNumber(s) => write!(f, "Invalid number: '{s}'"),
|
||||||
Self::MalformedChar(s) => write!(f, "Invalid character: '{}'", s),
|
Self::MalformedChar(s) => write!(f, "Invalid character: '{s}'"),
|
||||||
Self::MalformedIdentifier(s) => write!(f, "Variable name is not proper: '{}'", s),
|
Self::MalformedIdentifier(s) => write!(f, "Variable name is not proper: '{s}'"),
|
||||||
Self::UnterminatedString => f.write_str("Open string is not terminated"),
|
Self::UnterminatedString => f.write_str("Open string is not terminated"),
|
||||||
Self::StringTooLong(max) => write!(
|
Self::StringTooLong(max) => write!(
|
||||||
f,
|
f,
|
||||||
@ -50,7 +50,7 @@ impl fmt::Display for LexError {
|
|||||||
max
|
max
|
||||||
),
|
),
|
||||||
Self::ImproperSymbol(s, d) if d.is_empty() => {
|
Self::ImproperSymbol(s, d) if d.is_empty() => {
|
||||||
write!(f, "Invalid symbol encountered: '{}'", s)
|
write!(f, "Invalid symbol encountered: '{s}'")
|
||||||
}
|
}
|
||||||
Self::ImproperSymbol(.., d) => f.write_str(d),
|
Self::ImproperSymbol(.., d) => f.write_str(d),
|
||||||
}
|
}
|
||||||
|
@ -407,7 +407,7 @@ impl Scope<'_> {
|
|||||||
/// Find an entry in the [`Scope`], starting from the last.
|
/// Find an entry in the [`Scope`], starting from the last.
|
||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) fn get_index(&self, name: &str) -> Option<(usize, AccessMode)> {
|
pub(crate) fn search(&self, name: &str) -> Option<usize> {
|
||||||
let len = self.len();
|
let len = self.len();
|
||||||
|
|
||||||
self.names
|
self.names
|
||||||
@ -417,7 +417,7 @@ impl Scope<'_> {
|
|||||||
.find_map(|(i, key)| {
|
.find_map(|(i, key)| {
|
||||||
if name == key {
|
if name == key {
|
||||||
let index = len - 1 - i;
|
let index = len - 1 - i;
|
||||||
Some((index, self.values[index].access_mode()))
|
Some(index)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -467,10 +467,11 @@ impl Scope<'_> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn is_constant(&self, name: &str) -> Option<bool> {
|
pub fn is_constant(&self, name: &str) -> Option<bool> {
|
||||||
self.get_index(name).map(|(.., access)| match access {
|
self.search(name)
|
||||||
AccessMode::ReadWrite => false,
|
.map(|n| match self.values[n].access_mode() {
|
||||||
AccessMode::ReadOnly => true,
|
AccessMode::ReadWrite => false,
|
||||||
})
|
AccessMode::ReadOnly => true,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
/// Update the value of the named entry in the [`Scope`] if it already exists and is not constant.
|
/// Update the value of the named entry in the [`Scope`] if it already exists and is not constant.
|
||||||
/// Push a new entry with the value into the [`Scope`] if the name doesn't exist or if the
|
/// Push a new entry with the value into the [`Scope`] if the name doesn't exist or if the
|
||||||
@ -503,7 +504,10 @@ impl Scope<'_> {
|
|||||||
name: impl AsRef<str> + Into<Identifier>,
|
name: impl AsRef<str> + Into<Identifier>,
|
||||||
value: impl Variant + Clone,
|
value: impl Variant + Clone,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
match self.get_index(name.as_ref()) {
|
match self
|
||||||
|
.search(name.as_ref())
|
||||||
|
.map(|n| (n, self.values[n].access_mode()))
|
||||||
|
{
|
||||||
None | Some((.., AccessMode::ReadOnly)) => {
|
None | Some((.., AccessMode::ReadOnly)) => {
|
||||||
self.push(name, value);
|
self.push(name, value);
|
||||||
}
|
}
|
||||||
@ -542,7 +546,10 @@ impl Scope<'_> {
|
|||||||
name: impl AsRef<str> + Into<Identifier>,
|
name: impl AsRef<str> + Into<Identifier>,
|
||||||
value: impl Variant + Clone,
|
value: impl Variant + Clone,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
match self.get_index(name.as_ref()) {
|
match self
|
||||||
|
.search(name.as_ref())
|
||||||
|
.map(|n| (n, self.values[n].access_mode()))
|
||||||
|
{
|
||||||
None => {
|
None => {
|
||||||
self.push(name, value);
|
self.push(name, value);
|
||||||
}
|
}
|
||||||
@ -576,7 +583,7 @@ impl Scope<'_> {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get(&self, name: &str) -> Option<&Dynamic> {
|
pub fn get(&self, name: &str) -> Option<&Dynamic> {
|
||||||
self.get_index(name).map(|(index, _)| &self.values[index])
|
self.search(name).map(|index| &self.values[index])
|
||||||
}
|
}
|
||||||
/// Remove the last entry in the [`Scope`] by the specified name and return its value.
|
/// Remove the last entry in the [`Scope`] by the specified name and return its value.
|
||||||
///
|
///
|
||||||
@ -607,7 +614,7 @@ impl Scope<'_> {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn remove<T: Variant + Clone>(&mut self, name: &str) -> Option<T> {
|
pub fn remove<T: Variant + Clone>(&mut self, name: &str) -> Option<T> {
|
||||||
self.get_index(name).and_then(|(index, _)| {
|
self.search(name).and_then(|index| {
|
||||||
self.names.remove(index);
|
self.names.remove(index);
|
||||||
self.aliases.remove(index);
|
self.aliases.remove(index);
|
||||||
self.values.remove(index).try_cast()
|
self.values.remove(index).try_cast()
|
||||||
@ -639,9 +646,9 @@ impl Scope<'_> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_mut(&mut self, name: &str) -> Option<&mut Dynamic> {
|
pub fn get_mut(&mut self, name: &str) -> Option<&mut Dynamic> {
|
||||||
self.get_index(name)
|
self.search(name)
|
||||||
.and_then(move |(index, access)| match access {
|
.and_then(move |n| match self.values[n].access_mode() {
|
||||||
AccessMode::ReadWrite => Some(self.get_mut_by_index(index)),
|
AccessMode::ReadWrite => Some(self.get_mut_by_index(n)),
|
||||||
AccessMode::ReadOnly => None,
|
AccessMode::ReadOnly => None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -685,7 +692,7 @@ impl Scope<'_> {
|
|||||||
name: impl AsRef<str> + Into<Identifier>,
|
name: impl AsRef<str> + Into<Identifier>,
|
||||||
alias: impl Into<Identifier>,
|
alias: impl Into<Identifier>,
|
||||||
) {
|
) {
|
||||||
if let Some((index, ..)) = self.get_index(name.as_ref()) {
|
if let Some(index) = self.search(name.as_ref()) {
|
||||||
let alias = match alias.into() {
|
let alias = match alias.into() {
|
||||||
x if x.is_empty() => name.into(),
|
x if x.is_empty() => name.into(),
|
||||||
x => x,
|
x => x,
|
||||||
|
@ -87,7 +87,7 @@ fn test_constant_mut() -> Result<(), Box<EvalAltResult>> {
|
|||||||
"
|
"
|
||||||
)
|
)
|
||||||
.expect_err("should error"),
|
.expect_err("should error"),
|
||||||
EvalAltResult::ErrorAssignmentToConstant(..)
|
EvalAltResult::ErrorNonPureMethodCallOnConstant(..)
|
||||||
));
|
));
|
||||||
|
|
||||||
let mut scope = Scope::new();
|
let mut scope = Scope::new();
|
||||||
@ -120,7 +120,7 @@ fn test_constant_mut() -> Result<(), Box<EvalAltResult>> {
|
|||||||
*engine
|
*engine
|
||||||
.run_with_scope(&mut scope, "MY_NUMBER.value = 42;")
|
.run_with_scope(&mut scope, "MY_NUMBER.value = 42;")
|
||||||
.expect_err("should error"),
|
.expect_err("should error"),
|
||||||
EvalAltResult::ErrorAssignmentToConstant(..)
|
EvalAltResult::ErrorNonPureMethodCallOnConstant(..)
|
||||||
));
|
));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -2,10 +2,10 @@
|
|||||||
#![cfg(not(feature = "no_module"))]
|
#![cfg(not(feature = "no_module"))]
|
||||||
|
|
||||||
use rhai::plugin::*;
|
use rhai::plugin::*;
|
||||||
use rhai::{Engine, EvalAltResult, INT};
|
use rhai::{Engine, EvalAltResult, Scope, INT};
|
||||||
|
|
||||||
mod test {
|
mod test {
|
||||||
use rhai::plugin::*;
|
use super::*;
|
||||||
|
|
||||||
#[export_module]
|
#[export_module]
|
||||||
pub mod special_array_package {
|
pub mod special_array_package {
|
||||||
@ -119,7 +119,7 @@ fn test_plugins_package() -> Result<(), Box<EvalAltResult>> {
|
|||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
matches!(*engine.run("const A = [1, 2, 3]; A.test(42);").expect_err("should error"),
|
matches!(*engine.run("const A = [1, 2, 3]; A.test(42);").expect_err("should error"),
|
||||||
EvalAltResult::ErrorAssignmentToConstant(x, ..) if x == "array")
|
EvalAltResult::ErrorNonPureMethodCallOnConstant(x, ..) if x == "test")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,3 +170,57 @@ fn test_plugins_parameters() -> Result<(), Box<EvalAltResult>> {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_pointer_width = "64")]
|
||||||
|
mod handle {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq, Clone, Copy, Hash)]
|
||||||
|
pub struct WorldHandle(usize);
|
||||||
|
pub type World = Vec<i64>;
|
||||||
|
|
||||||
|
impl From<&mut World> for WorldHandle {
|
||||||
|
fn from(world: &mut World) -> Self {
|
||||||
|
Self::new(world)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsMut<World> for WorldHandle {
|
||||||
|
fn as_mut(&mut self) -> &mut World {
|
||||||
|
unsafe { std::mem::transmute(self.0) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WorldHandle {
|
||||||
|
pub fn new(world: &mut World) -> Self {
|
||||||
|
Self(unsafe { std::mem::transmute(world) })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[export_module]
|
||||||
|
pub mod handle_module {
|
||||||
|
pub type Handle = WorldHandle;
|
||||||
|
|
||||||
|
#[rhai_fn(get = "len")]
|
||||||
|
pub fn len(world: &mut Handle) -> INT {
|
||||||
|
world.as_mut().len() as INT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_module_handle() -> Result<(), Box<EvalAltResult>> {
|
||||||
|
let mut engine = Engine::new();
|
||||||
|
|
||||||
|
engine.register_global_module(exported_module!(handle_module).into());
|
||||||
|
|
||||||
|
let mut scope = Scope::new();
|
||||||
|
|
||||||
|
let world: &mut World = &mut vec![42];
|
||||||
|
scope.push("world", WorldHandle::from(world));
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
assert_eq!(engine.eval_with_scope::<INT>(&mut scope, "world.len")?, 1);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -52,7 +52,7 @@ fn test_switch() -> Result<(), Box<EvalAltResult>> {
|
|||||||
123
|
123
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
engine.eval::<INT>("let x = timestamp(); switch x { 1 => 123, _ => 42 }")?,
|
engine.eval_with_scope::<INT>(&mut scope, "switch x { 424242 => 123, _ => 42 }")?,
|
||||||
42
|
42
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
#![cfg(not(feature = "no_std"))]
|
#![cfg(not(feature = "no_time"))]
|
||||||
#![cfg(not(target_family = "wasm"))]
|
|
||||||
|
|
||||||
use rhai::{Engine, EvalAltResult};
|
use rhai::{Engine, EvalAltResult};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user