Skip to content

Commit

Permalink
Merge pull request #750 from schungx/master
Browse files Browse the repository at this point in the history
Use full version numbers.
  • Loading branch information
schungx committed Aug 3, 2023
2 parents ffd48c4 + 9184fdd commit 80a254f
Show file tree
Hide file tree
Showing 68 changed files with 4,529 additions and 3,671 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@ Enhancements
------------

* [`once_cell`](https://crates.io/crates/once_cell) is used in `std` environments instead of the home-brew `SusLock` (which is still kept for `no-std`).
* Originally, unit tests use the `?` operator liberally to simplify the code. However, this causes the loss of proper line numbers when it fails, making it difficult to identify the exact location of the failure. This is now fixed by using `unwrap()` instead.

New features
------------

* Added `Engine::max_variables` and `Engine::set_max_variables` to limit the maximum number of variables allowed within a scope at any time. This is to guard against defining a huge number of variables containing large data just beyond individual data size limits. When `max_variables` is exceeded a new error, `ErrorTooManyVariables`, is returned.
* Added `zip` function for arrays.


Version 1.15.1
Expand Down
144 changes: 72 additions & 72 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,110 +18,110 @@ keywords = ["scripting", "scripting-engine", "scripting-language", "embedded"]
categories = ["no-std", "embedded", "wasm", "parser-implementations"]

[dependencies]
smallvec = { version = "1.7", default-features = false, features = ["union", "const_new", "const_generics"] }
smallvec = { version = "1.7.0", default-features = false, features = ["union", "const_new", "const_generics"] }
ahash = { version = "0.8.2", default-features = false, features = ["compile-time-rng"] }
num-traits = { version = "0.2", default-features = false }
once_cell = { version = "1", default-features = false, features = ["race"] }
bitflags = { version = "2", default-features = false }
smartstring = { version = "1", default-features = false }
num-traits = { version = "0.2.0", default-features = false }
once_cell = { version = "1.7.0", default-features = false, features = ["race"] }
bitflags = { version = "2.0.0", default-features = false }
smartstring = { version = "1.0.0", default-features = false }
rhai_codegen = { version = "1.5.0", path = "codegen", default-features = false }

no-std-compat = { git = "https://gitlab.com/jD91mZM2/no-std-compat", version = "0.4.1", default-features = false, features = ["alloc"], optional = true }
libm = { version = "0.2", default-features = false, optional = true }
hashbrown = { version = "0.13", optional = true }
core-error = { version = "0.0", default-features = false, features = ["alloc"], optional = true }
serde = { version = "1.0", default-features = false, features = ["derive", "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 }
rust_decimal = { version = "1.16", default-features = false, features = ["maths"], optional = true }
getrandom = { version = "0.2", optional = true }
rustyline = { version = "11", optional = true }
document-features = { version = "0.2", optional = true }
libm = { version = "0.2.0", default-features = false, optional = true }
hashbrown = { version = "0.13.1", optional = true }
core-error = { version = "0.0.0", default-features = false, features = ["alloc"], optional = true }
serde = { version = "1.0.96", default-features = false, features = ["derive", "alloc"], optional = true }
serde_json = { version = "1.0.45", default-features = false, features = ["alloc"], optional = true }
unicode-xid = { version = "0.2.0", default-features = false, optional = true }
rust_decimal = { version = "1.16.0", default-features = false, features = ["maths"], optional = true }
getrandom = { version = "0.2.0", optional = true }
rustyline = { version = "12.0.0", optional = true }
document-features = { version = "0.2.0", optional = true }

[dev-dependencies]
rmp-serde = "1.1"
serde_json = { version = "1.0", default-features = false, features = ["alloc"] }
rmp-serde = "1.1.0"
serde_json = { version = "1.0.45", default-features = false, features = ["alloc"] }

[features]

## Default features: `std`, uses runtime random numbers for hashing.
default = ["std", "ahash/runtime-rng"] # ahash/runtime-rng trumps ahash/compile-time-rng
default = ["std", "ahash/runtime-rng"] # ahash/runtime-rng trumps ahash/compile-time-rng
## Standard features: uses compile-time random number for hashing.
std = ["once_cell/std", "ahash/std", "num-traits/std", "smartstring/std"]

#! ### Enable Special Functionalities

## Require that all data types implement `Send + Sync` (for multi-threaded usage).
sync = []
## Add support for the [`Decimal`](https://crates.io/crates/rust_decimal) data type (acts as the system floating-point type under `no_float`).
decimal = ["rust_decimal"]
## Enable serialization/deserialization of Rhai data types via [`serde`](https://crates.io/crates/serde).
serde = ["dep:serde", "smartstring/serde", "smallvec/serde"]
## Allow [Unicode Standard Annex #31](https://unicode.org/reports/tr31/) for identifiers.
unicode-xid-ident = ["unicode-xid"]
## Enable functions metadata (including doc-comments); implies [`serde`](#feature-serde).
metadata = ["serde", "serde_json", "rhai_codegen/metadata", "smartstring/serde"]
## Expose internal data structures (e.g. `AST` nodes).
internals = []
## Enable the debugging interface (implies [`internals`](#feature-internals)).
debugging = ["internals"]
## Features and dependencies required by `bin` tools: `decimal`, `metadata`, `serde`, `debugging` and [`rustyline`](https://crates.io/crates/rustyline).
bin-features = ["decimal", "metadata", "serde", "debugging", "rustyline"]
## Require that all data types implement `Send + Sync` (for multi-threaded usage).
sync = []
## Add support for the [`Decimal`](https://crates.io/crates/rust_decimal) data type (acts as the system floating-point type under `no_float`).
decimal = ["rust_decimal"]
## Enable serialization/deserialization of Rhai data types via [`serde`](https://crates.io/crates/serde).
serde = ["dep:serde", "smartstring/serde", "smallvec/serde"]
## Allow [Unicode Standard Annex #31](https://unicode.org/reports/tr31/) for identifiers.
unicode-xid-ident = ["unicode-xid"]
## Enable functions metadata (including doc-comments); implies [`serde`](#feature-serde).
metadata = ["serde", "serde_json", "rhai_codegen/metadata", "smartstring/serde"]
## Expose internal data structures (e.g. `AST` nodes).
internals = []
## Enable the debugging interface (implies [`internals`](#feature-internals)).
debugging = ["internals"]
## Features and dependencies required by `bin` tools: `decimal`, `metadata`, `serde`, `debugging` and [`rustyline`](https://crates.io/crates/rustyline).
bin-features = ["decimal", "metadata", "serde", "debugging", "rustyline"]

#! ### System Configuration Features

## Use `f32` instead of `f64` as the system floating-point number type.
f32_float = []
## Use `i32` instead of `i64` for the system integer number type (useful for 32-bit architectures).
## All other integer types (e.g. `u8`) are disabled.
only_i32 = []
## Disable all integer types (e.g. `u8`) other than `i64`.
only_i64 = []
## Use `f32` instead of `f64` as the system floating-point number type.
f32_float = []
## Use `i32` instead of `i64` for the system integer number type (useful for 32-bit architectures).
## All other integer types (e.g. `u8`) are disabled.
only_i32 = []
## Disable all integer types (e.g. `u8`) other than `i64`.
only_i64 = []

#! ### Disable Language Features

## Remove support for floating-point numbers.
no_float = []
## Remove support for arrays and indexing.
no_index = []
## Remove support for custom types, properties, method-style calls and object maps.
no_object = []
## Remove support for time-stamps.
no_time = []
## Remove support for script-defined functions (implies [`no_closure`](#feature-no_closure)).
no_function = ["no_closure"]
## Remove support for capturing external variables in anonymous functions (i.e. closures).
no_closure = []
## Remove support for loading external modules.
no_module = []
## Remove support for custom syntax.
no_custom_syntax = []
## Remove support for floating-point numbers.
no_float = []
## Remove support for arrays and indexing.
no_index = []
## Remove support for custom types, properties, method-style calls and object maps.
no_object = []
## Remove support for time-stamps.
no_time = []
## Remove support for script-defined functions (implies [`no_closure`](#feature-no_closure)).
no_function = ["no_closure"]
## Remove support for capturing external variables in anonymous functions (i.e. closures).
no_closure = []
## Remove support for loading external modules.
no_module = []
## Remove support for custom syntax.
no_custom_syntax = []

#! ### Performance-Related Features

## Disable all safety checks.
unchecked = []
## Do not track position when parsing.
no_position = []
## Disable the script optimizer.
no_optimize = []
## Disable all safety checks.
unchecked = []
## Do not track position when parsing.
no_position = []
## Disable the script optimizer.
no_optimize = []

#! ### Compiling for `no-std`

## Turn on `no-std` compilation (nightly only).
no_std = ["no-std-compat", "num-traits/libm", "core-error", "libm", "hashbrown", "no_time"]
## Turn on `no-std` compilation (nightly only).
no_std = ["no-std-compat", "num-traits/libm", "core-error", "libm", "hashbrown", "no_time"]

#! ### JavaScript Interface for WASM

## Use [`wasm-bindgen`](https://crates.io/crates/wasm-bindgen) as JavaScript interface.
wasm-bindgen = ["getrandom/js", "instant/wasm-bindgen"]
## Use [`stdweb`](https://crates.io/crates/stdweb) as JavaScript interface.
stdweb = ["getrandom/js", "instant/stdweb"]
## Use [`wasm-bindgen`](https://crates.io/crates/wasm-bindgen) as JavaScript interface.
wasm-bindgen = ["getrandom/js", "instant/wasm-bindgen"]
## Use [`stdweb`](https://crates.io/crates/stdweb) as JavaScript interface.
stdweb = ["getrandom/js", "instant/stdweb"]

#! ### Features used in testing environments only

## Running under a testing environment.
testing-environ = []
## Running under a testing environment.
testing-environ = []

[[bin]]
name = "rhai-repl"
Expand Down Expand Up @@ -157,4 +157,4 @@ features = ["document-features", "metadata", "serde", "internals", "decimal", "d
[patch.crates-io]
# Notice that a custom modified version of `rustyline` is used which supports bracketed paste on Windows.
# This can be moved to the official version when bracketed paste is added.
rustyline = { git = "https://github.com/schungx/rustyline", branch = "v11" }
rustyline = { git = "https://github.com/schungx/rustyline", branch = "v12" }
10 changes: 5 additions & 5 deletions codegen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ default = []
metadata = []

[dependencies]
proc-macro2 = "1"
syn = { version = "1.0", features = ["full", "parsing", "printing", "proc-macro", "extra-traits"] }
quote = "1"
proc-macro2 = "1.0.0"
syn = { version = "1.0.0", features = ["full", "parsing", "printing", "proc-macro", "extra-traits"] }
quote = "1.0.0"

[dev-dependencies]
rhai = { path = "..", version = "1.12", features = ["metadata"] }
trybuild = "1"
rhai = { path = "..", version = "1.12.0", features = ["metadata"] }
trybuild = "1.0.0"
4 changes: 2 additions & 2 deletions src/ast/stmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -667,7 +667,7 @@ pub enum Stmt {
/// * [`NEGATED`][ASTFlags::NEGATED] = `until`
Do(Box<FlowControl>, ASTFlags, Position),
/// `for` `(` id `,` counter `)` `in` expr `{` stmt `}`
For(Box<(Ident, Ident, FlowControl)>, Position),
For(Box<(Ident, Option<Ident>, FlowControl)>, Position),
/// \[`export`\] `let`|`const` id `=` expr
///
/// ### Flags
Expand Down Expand Up @@ -721,7 +721,7 @@ pub enum Stmt {
/// This variant does not map to any language structure. It is currently only used only to
/// convert normal variables into shared variables when they are _captured_ by a closure.
#[cfg(not(feature = "no_closure"))]
Share(Box<crate::FnArgsVec<(crate::ast::Ident, Option<NonZeroUsize>)>>),
Share(Box<crate::FnArgsVec<(Ident, Option<NonZeroUsize>)>>),
}

impl Default for Stmt {
Expand Down
30 changes: 25 additions & 5 deletions src/eval/stmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,14 @@ impl Engine {
}
}

// Guard against too many variables
if !cfg!(feature = "unchecked")
&& index.is_none()
&& scope.len() >= self.max_variables()
{
return Err(ERR::ErrorTooManyVariables(*pos).into());
}

// Evaluate initial value
let mut value = self
.eval_expr(global, caches, scope, this_ptr, expr)?
Expand Down Expand Up @@ -464,9 +472,6 @@ impl Engine {
if let Some(index) = index {
value.set_access_mode(access);
*scope.get_mut_by_index(scope.len() - index.get()) = value;
} else if !cfg!(feature = "unchecked") && scope.len() >= self.max_variables() {
// Guard against too many variables
return Err(ERR::ErrorTooManyVariables(*pos).into());
} else {
scope.push_entry(var_name.name.clone(), access, value);
}
Expand Down Expand Up @@ -667,6 +672,14 @@ impl Engine {
Stmt::For(x, ..) => {
let (var_name, counter, FlowControl { expr, body, .. }) = &**x;

// Guard against too many variables
if !cfg!(feature = "unchecked") {
let max = self.max_variables() - counter.as_ref().map_or(0, |_| 1);
if scope.len() >= max {
return Err(ERR::ErrorTooManyVariables(var_name.pos).into());
}
}

let iter_obj = self
.eval_expr(global, caches, scope, this_ptr.as_deref_mut(), expr)?
.flatten();
Expand Down Expand Up @@ -702,7 +715,7 @@ impl Engine {
defer! { scope => rewind; let orig_scope_len = scope.len(); }

// Add the loop variables
let counter_index = (!counter.is_empty()).then(|| {
let counter_index = counter.as_ref().map(|counter| {
scope.push(counter.name.clone(), 0 as INT);
scope.len() - 1
});
Expand All @@ -729,7 +742,7 @@ impl Engine {
if index_value > crate::MAX_USIZE_INT {
return Err(ERR::ErrorArithmetic(
format!("for-loop counter overflow: {x}"),
counter.pos,
counter.as_ref().unwrap().pos,
)
.into());
}
Expand Down Expand Up @@ -799,6 +812,9 @@ impl Engine {
Err(err) if !err.is_catchable() => Err(err),
Err(mut err) => {
let err_value = match err.unwrap_inner() {
// No error variable
_ if catch_var.is_unit() => Dynamic::UNIT,

ERR::ErrorRuntime(x, ..) => x.clone(),

#[cfg(feature = "no_object")]
Expand Down Expand Up @@ -837,6 +853,10 @@ impl Engine {
defer! { scope if !catch_var.is_unit() => rewind; let orig_scope_len = scope.len(); }

if let Expr::Variable(x, ..) = catch_var {
// Guard against too many variables
if !cfg!(feature = "unchecked") && scope.len() >= self.max_variables() {
return Err(ERR::ErrorTooManyVariables(catch_var.position()).into());
}
scope.push(x.3.clone(), err_value);
}

Expand Down
50 changes: 50 additions & 0 deletions src/packages/array_basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1463,6 +1463,56 @@ pub mod array_functions {
)
})
}
/// Iterate through all elements in two arrays, applying a `mapper` function to them,
/// and return a new array containing the results.
///
/// # Function Parameters
///
/// * `array1`: First array
/// * `array2`: Second array
/// * `index` _(optional)_: current index in the array
///
/// # Example
///
/// ```rhai
/// let x = [1, 2, 3, 4, 5];
/// let y = [9, 8, 7, 6];
///
/// let z = x.zip(y, |a, b| a + b);
///
/// print(z); // prints [10, 10, 10, 10]
///
/// let z = x.zip(y, |a, b, i| a + b + i);
///
/// print(z); // prints [10, 11, 12, 13]
/// ```
#[rhai_fn(return_raw, pure)]
pub fn zip(
ctx: NativeCallContext,
array1: &mut Array,
array2: Array,
map: FnPtr,
) -> RhaiResultOf<Array> {
if array1.is_empty() && array2.is_empty() {
return Ok(Array::new());
}

array1
.iter_mut()
.zip(array2)
.enumerate()
.map(|(i, (x, y))| {
map.call_raw_with_extra_args(
"zip",
&ctx,
None,
[x.clone(), y],
[(i as INT).into()],
None,
)
})
.collect()
}
/// Sort the array based on applying the `comparer` function.
///
/// # Function Parameters
Expand Down

0 comments on commit 80a254f

Please sign in to comment.