commit
1616541df4
28
CHANGELOG.md
28
CHANGELOG.md
@ -1,9 +1,36 @@
|
|||||||
Rhai Release Notes
|
Rhai Release Notes
|
||||||
==================
|
==================
|
||||||
|
|
||||||
|
Version 1.6.1
|
||||||
|
=============
|
||||||
|
|
||||||
|
Bug fixes
|
||||||
|
---------
|
||||||
|
|
||||||
|
* Functions with `Dynamic` parameters now work in qualified calls from `import`ed modules.
|
||||||
|
* `rhai-repl` now compiles with the new patch version of `rustyline`.
|
||||||
|
|
||||||
|
Script-breaking changes
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
* `split` now splits a string by whitespaces instead of splitting it into individual characters. This is more in line with common practices.
|
||||||
|
* A new function `to_chars` for strings is added to split the string into individual characters.
|
||||||
|
|
||||||
|
Enhancements
|
||||||
|
------------
|
||||||
|
|
||||||
|
* Strings are now directly iterable (via `for .. in`) yielding individual characters.
|
||||||
|
|
||||||
|
|
||||||
Version 1.6.0
|
Version 1.6.0
|
||||||
=============
|
=============
|
||||||
|
|
||||||
|
This version, in particular, fixes a plugin macro hygiene error for the nightly compiler:
|
||||||
|
|
||||||
|
```text
|
||||||
|
error[E0425]: cannot find value `args` in this scope
|
||||||
|
```
|
||||||
|
|
||||||
Compiler version
|
Compiler version
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
@ -12,6 +39,7 @@ Compiler version
|
|||||||
Bug fixes
|
Bug fixes
|
||||||
---------
|
---------
|
||||||
|
|
||||||
|
* Fixed macro hygiene error with nightly compiler.
|
||||||
* Invalid property or method access such as `a.b::c.d` or `a.b::func()` no longer panics but properly returns a syntax error.
|
* Invalid property or method access such as `a.b::c.d` or `a.b::func()` no longer panics but properly returns a syntax error.
|
||||||
* `Scope::is_constant` now returns the correct value.
|
* `Scope::is_constant` now returns the correct value.
|
||||||
* Exporting a variable that contains a local function pointer (including anonymous function or closure) now raises a runtime error.
|
* Exporting a variable that contains a local function pointer (including anonymous function or closure) now raises a runtime error.
|
||||||
|
13
Cargo.toml
13
Cargo.toml
@ -3,7 +3,7 @@ members = [".", "codegen"]
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "rhai"
|
name = "rhai"
|
||||||
version = "1.6.0"
|
version = "1.6.1"
|
||||||
rust-version = "1.57"
|
rust-version = "1.57"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
authors = ["Jonathan Turner", "Lukáš Hozda", "Stephen Chung", "jhwgh1968"]
|
authors = ["Jonathan Turner", "Lukáš Hozda", "Stephen Chung", "jhwgh1968"]
|
||||||
@ -22,7 +22,7 @@ ahash = { version = "0.7", default-features = false }
|
|||||||
num-traits = { version = "0.2", default-features = false }
|
num-traits = { version = "0.2", default-features = false }
|
||||||
bitflags = { version = "1", default-features = false }
|
bitflags = { version = "1", default-features = false }
|
||||||
smartstring = { version = "1", default-features = false }
|
smartstring = { version = "1", default-features = false }
|
||||||
rhai_codegen = { version = "1.2", path = "codegen", default-features = false }
|
rhai_codegen = { version = "1.4", path = "codegen", default-features = false }
|
||||||
|
|
||||||
no-std-compat = { version = "0.4", default-features = false, features = ["alloc"], optional = true }
|
no-std-compat = { version = "0.4", default-features = false, features = ["alloc"], optional = true }
|
||||||
libm = { version = "0.2", default-features = false, optional = true }
|
libm = { version = "0.2", default-features = false, optional = true }
|
||||||
@ -31,9 +31,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 }
|
||||||
# notice that a custom modified version of `rustyline` is used which supports bracketed paste on Windows
|
rustyline = { version = "9", optional = true }
|
||||||
# this can be moved to the official version when bracketed paste is added
|
|
||||||
rustyline = { version = "9", optional = true, git = "https://github.com/schungx/rustyline" }
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
serde_bytes = "0.11"
|
serde_bytes = "0.11"
|
||||||
@ -91,3 +89,8 @@ instant = { version = "0.1.10" } # WASM implementation of std::time::Instant
|
|||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
features = ["metadata", "serde", "internals", "decimal", "debugging"]
|
features = ["metadata", "serde", "internals", "decimal", "debugging"]
|
||||||
|
|
||||||
|
[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" }
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
Rhai - Embedded Scripting for Rust
|
Rhai - Embedded Scripting for Rust
|
||||||
=================================
|
==================================
|
||||||
|
|
||||||
![GitHub last commit](https://img.shields.io/github/last-commit/rhaiscript/rhai?logo=github)
|
![GitHub last commit](https://img.shields.io/github/last-commit/rhaiscript/rhai?logo=github)
|
||||||
[![Build Status](https://github.com/rhaiscript/rhai/workflows/Build/badge.svg)](https://github.com/rhaiscript/rhai/actions)
|
[![Build Status](https://github.com/rhaiscript/rhai/workflows/Build/badge.svg)](https://github.com/rhaiscript/rhai/actions)
|
||||||
@ -11,6 +11,7 @@ Rhai - Embedded Scripting for Rust
|
|||||||
[![VS Code plugin installs](https://img.shields.io/visual-studio-marketplace/i/rhaiscript.vscode-rhai?logo=visual-studio-code&label=vs%20code)](https://marketplace.visualstudio.com/items?itemName=rhaiscript.vscode-rhai)
|
[![VS Code plugin installs](https://img.shields.io/visual-studio-marketplace/i/rhaiscript.vscode-rhai?logo=visual-studio-code&label=vs%20code)](https://marketplace.visualstudio.com/items?itemName=rhaiscript.vscode-rhai)
|
||||||
[![Sublime Text package downloads](https://img.shields.io/packagecontrol/dt/Rhai.svg?logo=sublime-text&label=sublime%20text)](https://packagecontrol.io/packages/Rhai)
|
[![Sublime Text package downloads](https://img.shields.io/packagecontrol/dt/Rhai.svg?logo=sublime-text&label=sublime%20text)](https://packagecontrol.io/packages/Rhai)
|
||||||
[![Discord Chat](https://img.shields.io/discord/767611025456889857.svg?logo=discord&label=discord)](https://discord.gg/HquqbYFcZ9)
|
[![Discord Chat](https://img.shields.io/discord/767611025456889857.svg?logo=discord&label=discord)](https://discord.gg/HquqbYFcZ9)
|
||||||
|
[![Forum](https://img.shields.io/discourse/topics?server=https%3A%2F%2Frhai.discourse.group&logo=discourse&label=forum)](https://rhai.discourse.group/)
|
||||||
[![Zulip Chat](https://img.shields.io/badge/zulip-join_chat-brightgreen.svg?logo=zulip)](https://rhaiscript.zulipchat.com)
|
[![Zulip Chat](https://img.shields.io/badge/zulip-join_chat-brightgreen.svg?logo=zulip)](https://rhaiscript.zulipchat.com)
|
||||||
[![Reddit Channel](https://img.shields.io/reddit/subreddit-subscribers/Rhai?logo=reddit&label=reddit)](https://www.reddit.com/r/Rhai)
|
[![Reddit Channel](https://img.shields.io/reddit/subreddit-subscribers/Rhai?logo=reddit&label=reddit)](https://www.reddit.com/r/Rhai)
|
||||||
|
|
||||||
@ -65,7 +66,7 @@ Protected against attacks
|
|||||||
|
|
||||||
|
|
||||||
For those who actually want their own language
|
For those who actually want their own language
|
||||||
---------------------------------------------
|
----------------------------------------------
|
||||||
|
|
||||||
* Use as a [DSL](https://rhai.rs/book/engine/dsl.html).
|
* Use as a [DSL](https://rhai.rs/book/engine/dsl.html).
|
||||||
* Disable certain [language features](https://rhai.rs/book/engine/options.html#language-features) such as [looping](https://rhai.rs/book/engine/disable-looping.html).
|
* Disable certain [language features](https://rhai.rs/book/engine/options.html#language-features) such as [looping](https://rhai.rs/book/engine/disable-looping.html).
|
||||||
|
@ -12,3 +12,7 @@ note: required by a bound in `rhai::Dynamic::cast`
|
|||||||
| pub fn cast<T: Any + Clone>(self) -> T {
|
| pub fn cast<T: Any + Clone>(self) -> T {
|
||||||
| ^^^^^ required by this bound in `rhai::Dynamic::cast`
|
| ^^^^^ required by this bound in `rhai::Dynamic::cast`
|
||||||
= note: this error originates in the attribute macro `export_fn` (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in the attribute macro `export_fn` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
help: consider annotating `NonClonable` with `#[derive(Clone)]`
|
||||||
|
|
|
||||||
|
3 | #[derive(Clone)]
|
||||||
|
|
|
||||||
|
@ -12,3 +12,7 @@ note: required by a bound in `rhai::Dynamic::cast`
|
|||||||
| pub fn cast<T: Any + Clone>(self) -> T {
|
| pub fn cast<T: Any + Clone>(self) -> T {
|
||||||
| ^^^^^ required by this bound in `rhai::Dynamic::cast`
|
| ^^^^^ required by this bound in `rhai::Dynamic::cast`
|
||||||
= note: this error originates in the attribute macro `export_fn` (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in the attribute macro `export_fn` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
help: consider annotating `NonClonable` with `#[derive(Clone)]`
|
||||||
|
|
|
||||||
|
3 | #[derive(Clone)]
|
||||||
|
|
|
||||||
|
@ -12,3 +12,7 @@ note: required by a bound in `rhai::Dynamic::from`
|
|||||||
| pub fn from<T: Variant + Clone>(value: T) -> Self {
|
| pub fn from<T: Variant + Clone>(value: T) -> Self {
|
||||||
| ^^^^^ required by this bound in `rhai::Dynamic::from`
|
| ^^^^^ required by this bound in `rhai::Dynamic::from`
|
||||||
= note: this error originates in the attribute macro `export_fn` (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in the attribute macro `export_fn` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
help: consider annotating `NonClonable` with `#[derive(Clone)]`
|
||||||
|
|
|
||||||
|
3 | #[derive(Clone)]
|
||||||
|
|
|
||||||
|
@ -13,3 +13,7 @@ note: required by a bound in `rhai::Dynamic::from`
|
|||||||
| pub fn from<T: Variant + Clone>(value: T) -> Self {
|
| pub fn from<T: Variant + Clone>(value: T) -> Self {
|
||||||
| ^^^^^ required by this bound in `rhai::Dynamic::from`
|
| ^^^^^ required by this bound in `rhai::Dynamic::from`
|
||||||
= note: this error originates in the attribute macro `export_module` (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in the attribute macro `export_module` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
help: consider annotating `NonClonable` with `#[derive(Clone)]`
|
||||||
|
|
|
||||||
|
3 | #[derive(Clone)]
|
||||||
|
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use crate::packages::iter_basic::{BitRange, CharsStream, StepRange};
|
||||||
use crate::{
|
use crate::{
|
||||||
Engine, ExclusiveRange, FnPtr, ImmutableString, InclusiveRange, Position, RhaiError, ERR,
|
Engine, ExclusiveRange, FnPtr, ImmutableString, InclusiveRange, Position, RhaiError, ERR,
|
||||||
};
|
};
|
||||||
@ -65,6 +66,41 @@ fn map_std_type_name(name: &str, shorthands: bool) -> &str {
|
|||||||
"RangeInclusive<i64>"
|
"RangeInclusive<i64>"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
if name == type_name::<BitRange>() {
|
||||||
|
return if shorthands { "range" } else { "BitRange" };
|
||||||
|
}
|
||||||
|
if name == type_name::<CharsStream>() {
|
||||||
|
return if shorthands { "range" } else { "CharStream" };
|
||||||
|
}
|
||||||
|
|
||||||
|
let step_range_name = type_name::<StepRange<u8>>();
|
||||||
|
let step_range_name = &step_range_name[..step_range_name.len() - 3];
|
||||||
|
|
||||||
|
if name.starts_with(step_range_name) && name.ends_with('>') {
|
||||||
|
return if shorthands {
|
||||||
|
"range"
|
||||||
|
} else {
|
||||||
|
let step_range_name = step_range_name.split("::").last().unwrap();
|
||||||
|
&step_range_name[..step_range_name.len() - 1]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
if name == type_name::<crate::packages::iter_basic::float::StepFloatRange>() {
|
||||||
|
return if shorthands {
|
||||||
|
"range"
|
||||||
|
} else {
|
||||||
|
"StepFloatRange"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#[cfg(feature = "decimal")]
|
||||||
|
if name == type_name::<crate::packages::iter_basic::decimal::StepDecimalRange>() {
|
||||||
|
return if shorthands {
|
||||||
|
"range"
|
||||||
|
} else {
|
||||||
|
"StepDecimalRange"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if name.starts_with("rhai::") {
|
if name.starts_with("rhai::") {
|
||||||
map_std_type_name(&name[6..], shorthands)
|
map_std_type_name(&name[6..], shorthands)
|
||||||
|
@ -636,9 +636,7 @@ impl Expr {
|
|||||||
/// `non_qualified` is ignored under `no_module`.
|
/// `non_qualified` is ignored under `no_module`.
|
||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) fn is_variable_access(&self, non_qualified: bool) -> bool {
|
pub(crate) fn is_variable_access(&self, _non_qualified: bool) -> bool {
|
||||||
let _non_qualified = non_qualified;
|
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
Self::Variable(x, ..) if _non_qualified && !x.1.is_empty() => false,
|
Self::Variable(x, ..) if _non_qualified && !x.1.is_empty() => false,
|
||||||
@ -651,9 +649,7 @@ impl Expr {
|
|||||||
/// `non_qualified` is ignored under `no_module`.
|
/// `non_qualified` is ignored under `no_module`.
|
||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) fn get_variable_name(&self, non_qualified: bool) -> Option<&str> {
|
pub(crate) fn get_variable_name(&self, _non_qualified: bool) -> Option<&str> {
|
||||||
let _non_qualified = non_qualified;
|
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
Self::Variable(x, ..) if _non_qualified && !x.1.is_empty() => None,
|
Self::Variable(x, ..) if _non_qualified && !x.1.is_empty() => None,
|
||||||
|
@ -321,7 +321,7 @@ fn debug_callback(
|
|||||||
let mut input = String::new();
|
let mut input = String::new();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
print!("rhai-dbg> ");
|
print!("dbg> ");
|
||||||
|
|
||||||
stdout().flush().expect("couldn't flush stdout");
|
stdout().flush().expect("couldn't flush stdout");
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@ use rhai::{Dynamic, Engine, EvalAltResult, Module, Scope, AST, INT};
|
|||||||
use rustyline::config::Builder;
|
use rustyline::config::Builder;
|
||||||
use rustyline::error::ReadlineError;
|
use rustyline::error::ReadlineError;
|
||||||
use rustyline::{Cmd, Editor, Event, EventHandler, KeyCode, KeyEvent, Modifiers, Movement};
|
use rustyline::{Cmd, Editor, Event, EventHandler, KeyCode, KeyEvent, Modifiers, Movement};
|
||||||
use smallvec::smallvec;
|
|
||||||
|
|
||||||
use std::{env, fs::File, io::Read, path::Path, process::exit};
|
use std::{env, fs::File, io::Read, path::Path, process::exit};
|
||||||
|
|
||||||
@ -223,40 +222,40 @@ fn setup_editor() -> Editor<()> {
|
|||||||
// On Windows, Esc clears the input buffer
|
// On Windows, Esc clears the input buffer
|
||||||
#[cfg(target_family = "windows")]
|
#[cfg(target_family = "windows")]
|
||||||
rl.bind_sequence(
|
rl.bind_sequence(
|
||||||
Event::KeySeq(smallvec![KeyEvent(KeyCode::Esc, Modifiers::empty())]),
|
Event::KeySeq(vec![KeyEvent(KeyCode::Esc, Modifiers::empty())]),
|
||||||
EventHandler::Simple(Cmd::Kill(Movement::WholeBuffer)),
|
EventHandler::Simple(Cmd::Kill(Movement::WholeBuffer)),
|
||||||
);
|
);
|
||||||
// On Windows, Ctrl-Z is undo
|
// On Windows, Ctrl-Z is undo
|
||||||
#[cfg(target_family = "windows")]
|
#[cfg(target_family = "windows")]
|
||||||
rl.bind_sequence(
|
rl.bind_sequence(
|
||||||
Event::KeySeq(smallvec![KeyEvent::ctrl('z')]),
|
Event::KeySeq(vec![KeyEvent::ctrl('z')]),
|
||||||
EventHandler::Simple(Cmd::Undo(1)),
|
EventHandler::Simple(Cmd::Undo(1)),
|
||||||
);
|
);
|
||||||
// Map Ctrl-Enter to insert a new line - bypass need for `\` continuation
|
// Map Ctrl-Enter to insert a new line - bypass need for `\` continuation
|
||||||
rl.bind_sequence(
|
rl.bind_sequence(
|
||||||
Event::KeySeq(smallvec![KeyEvent(KeyCode::Char('J'), Modifiers::CTRL)]),
|
Event::KeySeq(vec![KeyEvent(KeyCode::Char('J'), Modifiers::CTRL)]),
|
||||||
EventHandler::Simple(Cmd::Newline),
|
EventHandler::Simple(Cmd::Newline),
|
||||||
);
|
);
|
||||||
rl.bind_sequence(
|
rl.bind_sequence(
|
||||||
Event::KeySeq(smallvec![KeyEvent(KeyCode::Enter, Modifiers::CTRL)]),
|
Event::KeySeq(vec![KeyEvent(KeyCode::Enter, Modifiers::CTRL)]),
|
||||||
EventHandler::Simple(Cmd::Newline),
|
EventHandler::Simple(Cmd::Newline),
|
||||||
);
|
);
|
||||||
// Map Ctrl-Home and Ctrl-End for beginning/end of input
|
// Map Ctrl-Home and Ctrl-End for beginning/end of input
|
||||||
rl.bind_sequence(
|
rl.bind_sequence(
|
||||||
Event::KeySeq(smallvec![KeyEvent(KeyCode::Home, Modifiers::CTRL)]),
|
Event::KeySeq(vec![KeyEvent(KeyCode::Home, Modifiers::CTRL)]),
|
||||||
EventHandler::Simple(Cmd::Move(Movement::BeginningOfBuffer)),
|
EventHandler::Simple(Cmd::Move(Movement::BeginningOfBuffer)),
|
||||||
);
|
);
|
||||||
rl.bind_sequence(
|
rl.bind_sequence(
|
||||||
Event::KeySeq(smallvec![KeyEvent(KeyCode::End, Modifiers::CTRL)]),
|
Event::KeySeq(vec![KeyEvent(KeyCode::End, Modifiers::CTRL)]),
|
||||||
EventHandler::Simple(Cmd::Move(Movement::EndOfBuffer)),
|
EventHandler::Simple(Cmd::Move(Movement::EndOfBuffer)),
|
||||||
);
|
);
|
||||||
// Map Ctrl-Up and Ctrl-Down to skip up/down the history, even through multi-line histories
|
// Map Ctrl-Up and Ctrl-Down to skip up/down the history, even through multi-line histories
|
||||||
rl.bind_sequence(
|
rl.bind_sequence(
|
||||||
Event::KeySeq(smallvec![KeyEvent(KeyCode::Down, Modifiers::CTRL)]),
|
Event::KeySeq(vec![KeyEvent(KeyCode::Down, Modifiers::CTRL)]),
|
||||||
EventHandler::Simple(Cmd::NextHistory),
|
EventHandler::Simple(Cmd::NextHistory),
|
||||||
);
|
);
|
||||||
rl.bind_sequence(
|
rl.bind_sequence(
|
||||||
Event::KeySeq(smallvec![KeyEvent(KeyCode::Up, Modifiers::CTRL)]),
|
Event::KeySeq(vec![KeyEvent(KeyCode::Up, Modifiers::CTRL)]),
|
||||||
EventHandler::Simple(Cmd::PreviousHistory),
|
EventHandler::Simple(Cmd::PreviousHistory),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -371,11 +370,7 @@ fn main() {
|
|||||||
input.clear();
|
input.clear();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let prompt = if input.is_empty() {
|
let prompt = if input.is_empty() { "repl> " } else { " > " };
|
||||||
"rhai-repl> "
|
|
||||||
} else {
|
|
||||||
" > "
|
|
||||||
};
|
|
||||||
|
|
||||||
match rl.readline(prompt) {
|
match rl.readline(prompt) {
|
||||||
// Line continuation
|
// Line continuation
|
||||||
|
@ -295,9 +295,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Check a result to ensure that it is valid.
|
/// Check a result to ensure that it is valid.
|
||||||
pub(crate) fn check_return_value(&self, mut result: RhaiResult, pos: Position) -> RhaiResult {
|
pub(crate) fn check_return_value(&self, mut result: RhaiResult, _pos: Position) -> RhaiResult {
|
||||||
let _pos = pos;
|
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
Ok(ref mut r) => {
|
Ok(ref mut r) => {
|
||||||
// Concentrate all empty strings into one instance to save memory
|
// Concentrate all empty strings into one instance to save memory
|
||||||
|
@ -127,16 +127,14 @@ impl Engine {
|
|||||||
this_ptr: &mut Option<&mut Dynamic>,
|
this_ptr: &mut Option<&mut Dynamic>,
|
||||||
target: &mut Target,
|
target: &mut Target,
|
||||||
root: (&str, Position),
|
root: (&str, Position),
|
||||||
parent: &Expr,
|
_parent: &Expr,
|
||||||
rhs: &Expr,
|
rhs: &Expr,
|
||||||
parent_options: ASTFlags,
|
_parent_options: ASTFlags,
|
||||||
idx_values: &mut StaticVec<super::ChainArgument>,
|
idx_values: &mut StaticVec<super::ChainArgument>,
|
||||||
chain_type: ChainType,
|
chain_type: ChainType,
|
||||||
level: usize,
|
level: usize,
|
||||||
new_val: Option<((Dynamic, Position), (Option<OpAssignment>, Position))>,
|
new_val: Option<((Dynamic, Position), (Option<OpAssignment>, Position))>,
|
||||||
) -> RhaiResultOf<(Dynamic, bool)> {
|
) -> RhaiResultOf<(Dynamic, bool)> {
|
||||||
let _parent = parent;
|
|
||||||
let _parent_options = parent_options;
|
|
||||||
let is_ref_mut = target.is_ref();
|
let is_ref_mut = target.is_ref();
|
||||||
|
|
||||||
// Pop the last index value
|
// Pop the last index value
|
||||||
@ -671,7 +669,7 @@ impl Engine {
|
|||||||
this_ptr: &mut Option<&mut Dynamic>,
|
this_ptr: &mut Option<&mut Dynamic>,
|
||||||
expr: &Expr,
|
expr: &Expr,
|
||||||
parent_options: ASTFlags,
|
parent_options: ASTFlags,
|
||||||
parent_chain_type: ChainType,
|
_parent_chain_type: ChainType,
|
||||||
idx_values: &mut StaticVec<super::ChainArgument>,
|
idx_values: &mut StaticVec<super::ChainArgument>,
|
||||||
size: usize,
|
size: usize,
|
||||||
level: usize,
|
level: usize,
|
||||||
@ -679,8 +677,6 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
self.inc_operations(&mut global.num_operations, expr.position())?;
|
self.inc_operations(&mut global.num_operations, expr.position())?;
|
||||||
|
|
||||||
let _parent_chain_type = parent_chain_type;
|
|
||||||
|
|
||||||
match expr {
|
match expr {
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Expr::MethodCall(x, ..)
|
Expr::MethodCall(x, ..)
|
||||||
@ -850,18 +846,15 @@ impl Engine {
|
|||||||
state: &mut EvalState,
|
state: &mut EvalState,
|
||||||
lib: &[&Module],
|
lib: &[&Module],
|
||||||
target: &'t mut Dynamic,
|
target: &'t mut Dynamic,
|
||||||
idx: Dynamic,
|
mut idx: Dynamic,
|
||||||
idx_pos: Position,
|
idx_pos: Position,
|
||||||
add_if_not_found: bool,
|
_add_if_not_found: bool,
|
||||||
use_indexers: bool,
|
use_indexers: bool,
|
||||||
level: usize,
|
level: usize,
|
||||||
) -> RhaiResultOf<Target<'t>> {
|
) -> RhaiResultOf<Target<'t>> {
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
self.inc_operations(&mut global.num_operations, Position::NONE)?;
|
self.inc_operations(&mut global.num_operations, Position::NONE)?;
|
||||||
|
|
||||||
let mut idx = idx;
|
|
||||||
let _add_if_not_found = add_if_not_found;
|
|
||||||
|
|
||||||
match target {
|
match target {
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Dynamic(Union::Array(arr, ..)) => {
|
Dynamic(Union::Array(arr, ..)) => {
|
||||||
|
@ -16,9 +16,7 @@ impl Engine {
|
|||||||
///
|
///
|
||||||
/// Panics if any interior data is shared (should never happen).
|
/// Panics if any interior data is shared (should never happen).
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
pub(crate) fn calc_data_sizes(value: &Dynamic, top: bool) -> (usize, usize, usize) {
|
pub(crate) fn calc_data_sizes(value: &Dynamic, _top: bool) -> (usize, usize, usize) {
|
||||||
let _top = top;
|
|
||||||
|
|
||||||
match value.0 {
|
match value.0 {
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Union::Array(ref arr, ..) => {
|
Union::Array(ref arr, ..) => {
|
||||||
|
@ -195,7 +195,7 @@ impl Engine {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
fn resolve_fn<'s>(
|
fn resolve_fn<'s>(
|
||||||
&self,
|
&self,
|
||||||
global: &GlobalRuntimeState,
|
_global: &GlobalRuntimeState,
|
||||||
state: &'s mut EvalState,
|
state: &'s mut EvalState,
|
||||||
lib: &[&Module],
|
lib: &[&Module],
|
||||||
fn_name: &str,
|
fn_name: &str,
|
||||||
@ -204,8 +204,6 @@ impl Engine {
|
|||||||
allow_dynamic: bool,
|
allow_dynamic: bool,
|
||||||
is_op_assignment: bool,
|
is_op_assignment: bool,
|
||||||
) -> Option<&'s FnResolutionCacheEntry> {
|
) -> Option<&'s FnResolutionCacheEntry> {
|
||||||
let _global = global;
|
|
||||||
|
|
||||||
if hash_script == 0 {
|
if hash_script == 0 {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@ -576,7 +574,7 @@ impl Engine {
|
|||||||
/// all others are silently replaced by `()`!
|
/// all others are silently replaced by `()`!
|
||||||
pub(crate) fn exec_fn_call(
|
pub(crate) fn exec_fn_call(
|
||||||
&self,
|
&self,
|
||||||
scope: Option<&mut Scope>,
|
_scope: Option<&mut Scope>,
|
||||||
global: &mut GlobalRuntimeState,
|
global: &mut GlobalRuntimeState,
|
||||||
state: &mut EvalState,
|
state: &mut EvalState,
|
||||||
lib: &[&Module],
|
lib: &[&Module],
|
||||||
@ -584,7 +582,7 @@ impl Engine {
|
|||||||
hashes: FnCallHashes,
|
hashes: FnCallHashes,
|
||||||
args: &mut FnCallArgs,
|
args: &mut FnCallArgs,
|
||||||
is_ref_mut: bool,
|
is_ref_mut: bool,
|
||||||
is_method_call: bool,
|
_is_method_call: bool,
|
||||||
pos: Position,
|
pos: Position,
|
||||||
level: usize,
|
level: usize,
|
||||||
) -> RhaiResultOf<(Dynamic, bool)> {
|
) -> RhaiResultOf<(Dynamic, bool)> {
|
||||||
@ -600,9 +598,6 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
ensure_no_data_race(fn_name, args, is_ref_mut)?;
|
ensure_no_data_race(fn_name, args, is_ref_mut)?;
|
||||||
|
|
||||||
let _scope = scope;
|
|
||||||
let _is_method_call = is_method_call;
|
|
||||||
|
|
||||||
// These may be redirected from method style calls.
|
// These may be redirected from method style calls.
|
||||||
match fn_name {
|
match fn_name {
|
||||||
// Handle type_of()
|
// Handle type_of()
|
||||||
@ -1301,13 +1296,14 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Search for the root namespace
|
||||||
let module = self
|
let module = self
|
||||||
.search_imports(global, state, namespace)
|
.search_imports(global, state, namespace)
|
||||||
.ok_or_else(|| ERR::ErrorModuleNotFound(namespace.to_string(), namespace.position()))?;
|
.ok_or_else(|| ERR::ErrorModuleNotFound(namespace.to_string(), namespace.position()))?;
|
||||||
|
|
||||||
// First search in script-defined functions (can override built-in)
|
// First search script-defined functions in namespace (can override built-in)
|
||||||
let func = match module.get_qualified_fn(hash) {
|
let mut func = match module.get_qualified_fn(hash) {
|
||||||
// Then search in Rust functions
|
// Then search native Rust functions
|
||||||
None => {
|
None => {
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
self.inc_operations(&mut global.num_operations, pos)?;
|
self.inc_operations(&mut global.num_operations, pos)?;
|
||||||
@ -1320,6 +1316,41 @@ impl Engine {
|
|||||||
r => r,
|
r => r,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Check for `Dynamic` parameters.
|
||||||
|
//
|
||||||
|
// Note - This is done during every function call mismatch without cache,
|
||||||
|
// so hopefully the number of arguments should not be too many
|
||||||
|
// (expected because closures cannot be qualified).
|
||||||
|
if func.is_none() && !args.is_empty() {
|
||||||
|
let num_args = args.len();
|
||||||
|
let max_bitmask = 1usize << usize::min(num_args, MAX_DYNAMIC_PARAMETERS);
|
||||||
|
let mut bitmask = 1usize; // Bitmask of which parameter to replace with `Dynamic`
|
||||||
|
|
||||||
|
// Try all permutations with `Dynamic` wildcards
|
||||||
|
while bitmask < max_bitmask {
|
||||||
|
let hash_params = calc_fn_params_hash(args.iter().enumerate().map(|(i, a)| {
|
||||||
|
let mask = 1usize << (num_args - i - 1);
|
||||||
|
if bitmask & mask != 0 {
|
||||||
|
// Replace with `Dynamic`
|
||||||
|
TypeId::of::<Dynamic>()
|
||||||
|
} else {
|
||||||
|
a.type_id()
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
let hash_qualified_fn = combine_hashes(hash, hash_params);
|
||||||
|
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
self.inc_operations(&mut global.num_operations, pos)?;
|
||||||
|
|
||||||
|
if let Some(f) = module.get_qualified_fn(hash_qualified_fn) {
|
||||||
|
func = Some(f);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bitmask += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Clone first argument if the function is not a method after-all
|
// Clone first argument if the function is not a method after-all
|
||||||
if !func.map(|f| f.is_method()).unwrap_or(true) {
|
if !func.map(|f| f.is_method()).unwrap_or(true) {
|
||||||
if let Some(first) = first_arg_value {
|
if let Some(first) = first_arg_value {
|
||||||
@ -1382,11 +1413,9 @@ impl Engine {
|
|||||||
state: &mut EvalState,
|
state: &mut EvalState,
|
||||||
lib: &[&Module],
|
lib: &[&Module],
|
||||||
script: &str,
|
script: &str,
|
||||||
pos: Position,
|
_pos: Position,
|
||||||
level: usize,
|
level: usize,
|
||||||
) -> RhaiResult {
|
) -> RhaiResult {
|
||||||
let _pos = pos;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
self.inc_operations(&mut global.num_operations, _pos)?;
|
self.inc_operations(&mut global.num_operations, _pos)?;
|
||||||
|
|
||||||
|
@ -38,13 +38,11 @@ impl Engine {
|
|||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
fn make_error(
|
fn make_error(
|
||||||
name: String,
|
name: String,
|
||||||
fn_def: &ScriptFnDef,
|
_fn_def: &ScriptFnDef,
|
||||||
global: &GlobalRuntimeState,
|
global: &GlobalRuntimeState,
|
||||||
err: RhaiError,
|
err: RhaiError,
|
||||||
pos: Position,
|
pos: Position,
|
||||||
) -> RhaiResult {
|
) -> RhaiResult {
|
||||||
let _fn_def = fn_def;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
let source = _fn_def
|
let source = _fn_def
|
||||||
.environ
|
.environ
|
||||||
@ -232,13 +230,11 @@ impl Engine {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) fn has_script_fn(
|
pub(crate) fn has_script_fn(
|
||||||
&self,
|
&self,
|
||||||
global: Option<&GlobalRuntimeState>,
|
_global: Option<&GlobalRuntimeState>,
|
||||||
state: &mut EvalState,
|
state: &mut EvalState,
|
||||||
lib: &[&Module],
|
lib: &[&Module],
|
||||||
hash_script: u64,
|
hash_script: u64,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let _global = global;
|
|
||||||
|
|
||||||
let cache = state.fn_resolution_cache_mut();
|
let cache = state.fn_resolution_cache_mut();
|
||||||
|
|
||||||
if let Some(result) = cache.get(&hash_script).map(|v| v.is_some()) {
|
if let Some(result) = cache.get(&hash_script).map(|v| v.is_some()) {
|
||||||
|
@ -417,20 +417,68 @@ impl Module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Map a custom type to a friendly display name.
|
/// Map a custom type to a friendly display name.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use rhai::Module;
|
||||||
|
/// #[derive(Clone)]
|
||||||
|
/// struct TestStruct;
|
||||||
|
///
|
||||||
|
/// let name = std::any::type_name::<TestStruct>();
|
||||||
|
///
|
||||||
|
/// let mut module = Module::new();
|
||||||
|
///
|
||||||
|
/// module.set_custom_type::<TestStruct>("MyType");
|
||||||
|
///
|
||||||
|
/// assert_eq!(module.get_custom_type(name), Some("MyType"));
|
||||||
|
/// ```
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn set_custom_type<T>(&mut self, name: &str) {
|
pub fn set_custom_type<T>(&mut self, name: &str) -> &mut Self {
|
||||||
self.custom_types.add_type::<T>(name)
|
self.custom_types.add_type::<T>(name);
|
||||||
|
self
|
||||||
}
|
}
|
||||||
/// Map a custom type to a friendly display name.
|
/// Map a custom type to a friendly display name.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use rhai::Module;
|
||||||
|
/// #[derive(Clone)]
|
||||||
|
/// struct TestStruct;
|
||||||
|
///
|
||||||
|
/// let name = std::any::type_name::<TestStruct>();
|
||||||
|
///
|
||||||
|
/// let mut module = Module::new();
|
||||||
|
///
|
||||||
|
/// module.set_custom_type_raw(name, "MyType");
|
||||||
|
///
|
||||||
|
/// assert_eq!(module.get_custom_type(name), Some("MyType"));
|
||||||
|
/// ```
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn set_custom_type_raw(
|
pub fn set_custom_type_raw(
|
||||||
&mut self,
|
&mut self,
|
||||||
type_name: impl Into<Identifier>,
|
type_name: impl Into<Identifier>,
|
||||||
name: impl Into<Identifier>,
|
name: impl Into<Identifier>,
|
||||||
) {
|
) -> &mut Self {
|
||||||
self.custom_types.add(type_name, name)
|
self.custom_types.add(type_name, name);
|
||||||
|
self
|
||||||
}
|
}
|
||||||
/// Get the display name of a registered custom type.
|
/// Get the display name of a registered custom type.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use rhai::Module;
|
||||||
|
/// #[derive(Clone)]
|
||||||
|
/// struct TestStruct;
|
||||||
|
///
|
||||||
|
/// let name = std::any::type_name::<TestStruct>();
|
||||||
|
///
|
||||||
|
/// let mut module = Module::new();
|
||||||
|
///
|
||||||
|
/// module.set_custom_type::<TestStruct>("MyType");
|
||||||
|
///
|
||||||
|
/// assert_eq!(module.get_custom_type(name), Some("MyType"));
|
||||||
|
/// ```
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn get_custom_type(&self, key: &str) -> Option<&str> {
|
pub fn get_custom_type(&self, key: &str) -> Option<&str> {
|
||||||
self.custom_types.get(key)
|
self.custom_types.get(key)
|
||||||
|
@ -863,7 +863,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Optimize an [expression][Expr].
|
/// Optimize an [expression][Expr].
|
||||||
fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, chaining: bool) {
|
fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, _chaining: bool) {
|
||||||
// These keywords are handled specially
|
// These keywords are handled specially
|
||||||
const DONT_EVAL_KEYWORDS: &[&str] = &[
|
const DONT_EVAL_KEYWORDS: &[&str] = &[
|
||||||
KEYWORD_PRINT, // side effects
|
KEYWORD_PRINT, // side effects
|
||||||
@ -871,8 +871,6 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, chaining: bool) {
|
|||||||
KEYWORD_EVAL, // arbitrary scripts
|
KEYWORD_EVAL, // arbitrary scripts
|
||||||
];
|
];
|
||||||
|
|
||||||
let _chaining = chaining;
|
|
||||||
|
|
||||||
match expr {
|
match expr {
|
||||||
// {}
|
// {}
|
||||||
Expr::Stmt(x) if x.is_empty() => { state.set_dirty(); *expr = Expr::Unit(x.position()) }
|
Expr::Stmt(x) if x.is_empty() => { state.set_dirty(); *expr = Expr::Unit(x.position()) }
|
||||||
|
@ -17,7 +17,7 @@ use std::ops::{Add, Sub};
|
|||||||
|
|
||||||
// Range iterator with step
|
// Range iterator with step
|
||||||
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
|
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
|
||||||
struct StepRange<T>(T, T, T)
|
pub struct StepRange<T>(T, T, T)
|
||||||
where
|
where
|
||||||
T: Variant + Copy + PartialOrd + Add<Output = T> + Sub<Output = T>;
|
T: Variant + Copy + PartialOrd + Add<Output = T> + Sub<Output = T>;
|
||||||
|
|
||||||
@ -115,7 +115,7 @@ impl<T> FusedIterator for StepRange<T> where
|
|||||||
|
|
||||||
// Bit-field iterator with step
|
// Bit-field iterator with step
|
||||||
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
|
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
|
||||||
struct BitRange(INT, INT, usize);
|
pub struct BitRange(INT, INT, usize);
|
||||||
|
|
||||||
impl BitRange {
|
impl BitRange {
|
||||||
pub fn new(value: INT, from: INT, len: INT) -> RhaiResultOf<Self> {
|
pub fn new(value: INT, from: INT, len: INT) -> RhaiResultOf<Self> {
|
||||||
@ -166,7 +166,7 @@ impl ExactSizeIterator for BitRange {
|
|||||||
|
|
||||||
// String iterator over characters
|
// String iterator over characters
|
||||||
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
|
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
|
||||||
struct CharsStream(Vec<char>, usize);
|
pub struct CharsStream(Vec<char>, usize);
|
||||||
|
|
||||||
impl CharsStream {
|
impl CharsStream {
|
||||||
pub fn new(string: &str, from: INT, len: INT) -> Self {
|
pub fn new(string: &str, from: INT, len: INT) -> Self {
|
||||||
@ -237,6 +237,134 @@ impl ExactSizeIterator for CharsStream {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
pub mod float {
|
||||||
|
use super::*;
|
||||||
|
use crate::FLOAT;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
|
pub struct StepFloatRange(FLOAT, FLOAT, FLOAT);
|
||||||
|
|
||||||
|
impl StepFloatRange {
|
||||||
|
pub fn new(from: FLOAT, to: FLOAT, step: FLOAT) -> RhaiResultOf<Self> {
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
if step == 0.0 {
|
||||||
|
return Err(crate::ERR::ErrorInFunctionCall(
|
||||||
|
"range".to_string(),
|
||||||
|
"".to_string(),
|
||||||
|
crate::ERR::ErrorArithmetic(
|
||||||
|
"step value cannot be zero".to_string(),
|
||||||
|
Position::NONE,
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
Position::NONE,
|
||||||
|
)
|
||||||
|
.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Self(from, to, step))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Iterator for StepFloatRange {
|
||||||
|
type Item = FLOAT;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<FLOAT> {
|
||||||
|
if self.0 == self.1 {
|
||||||
|
None
|
||||||
|
} else if self.0 < self.1 {
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
if self.2 < 0.0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let v = self.0;
|
||||||
|
let n = self.0 + self.2;
|
||||||
|
|
||||||
|
self.0 = if n >= self.1 { self.1 } else { n };
|
||||||
|
Some(v)
|
||||||
|
} else {
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
if self.2 > 0.0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let v = self.0;
|
||||||
|
let n = self.0 + self.2;
|
||||||
|
|
||||||
|
self.0 = if n <= self.1 { self.1 } else { n };
|
||||||
|
Some(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FusedIterator for StepFloatRange {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "decimal")]
|
||||||
|
pub mod decimal {
|
||||||
|
use super::*;
|
||||||
|
use rust_decimal::Decimal;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
|
||||||
|
pub struct StepDecimalRange(Decimal, Decimal, Decimal);
|
||||||
|
|
||||||
|
impl StepDecimalRange {
|
||||||
|
pub fn new(from: Decimal, to: Decimal, step: Decimal) -> RhaiResultOf<Self> {
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
if step.is_zero() {
|
||||||
|
return Err(crate::ERR::ErrorInFunctionCall(
|
||||||
|
"range".to_string(),
|
||||||
|
"".to_string(),
|
||||||
|
crate::ERR::ErrorArithmetic(
|
||||||
|
"step value cannot be zero".to_string(),
|
||||||
|
Position::NONE,
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
Position::NONE,
|
||||||
|
)
|
||||||
|
.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Self(from, to, step))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Iterator for StepDecimalRange {
|
||||||
|
type Item = Decimal;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Decimal> {
|
||||||
|
if self.0 == self.1 {
|
||||||
|
None
|
||||||
|
} else if self.0 < self.1 {
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
if self.2.is_sign_negative() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let v = self.0;
|
||||||
|
let n = self.0 + self.2;
|
||||||
|
|
||||||
|
self.0 = if n >= self.1 { self.1 } else { n };
|
||||||
|
Some(v)
|
||||||
|
} else {
|
||||||
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
if self.2.is_sign_positive() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let v = self.0;
|
||||||
|
let n = self.0 + self.2;
|
||||||
|
|
||||||
|
self.0 = if n <= self.1 { self.1 } else { n };
|
||||||
|
Some(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FusedIterator for StepDecimalRange {}
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! reg_range {
|
macro_rules! reg_range {
|
||||||
($lib:ident | $x:expr => $( $y:ty ),*) => {
|
($lib:ident | $x:expr => $( $y:ty ),*) => {
|
||||||
$(
|
$(
|
||||||
@ -326,62 +454,9 @@ def_package! {
|
|||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
{
|
{
|
||||||
use crate::FLOAT;
|
lib.set_iterator::<float::StepFloatRange>();
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
let _hash = lib.set_native_fn("range", float::StepFloatRange::new);
|
||||||
struct StepFloatRange(FLOAT, FLOAT, FLOAT);
|
|
||||||
|
|
||||||
impl StepFloatRange {
|
|
||||||
pub fn new(from: FLOAT, to: FLOAT, step: FLOAT) -> RhaiResultOf<Self> {
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
|
||||||
if step == 0.0 {
|
|
||||||
return Err(crate::ERR::ErrorInFunctionCall("range".to_string(), "".to_string(),
|
|
||||||
crate::ERR::ErrorArithmetic("step value cannot be zero".to_string(), Position::NONE).into(),
|
|
||||||
Position::NONE,
|
|
||||||
).into());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Self(from, to, step))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Iterator for StepFloatRange {
|
|
||||||
type Item = FLOAT;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<FLOAT> {
|
|
||||||
if self.0 == self.1 {
|
|
||||||
None
|
|
||||||
} else if self.0 < self.1 {
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
|
||||||
if self.2 < 0.0 {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let v = self.0;
|
|
||||||
let n = self.0 + self.2;
|
|
||||||
|
|
||||||
self.0 = if n >= self.1 { self.1 } else { n };
|
|
||||||
Some(v)
|
|
||||||
} else {
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
|
||||||
if self.2 > 0.0 {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let v = self.0;
|
|
||||||
let n = self.0 + self.2;
|
|
||||||
|
|
||||||
self.0 = if n <= self.1 { self.1 } else { n };
|
|
||||||
Some(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FusedIterator for StepFloatRange {}
|
|
||||||
|
|
||||||
lib.set_iterator::<StepFloatRange>();
|
|
||||||
|
|
||||||
let _hash = lib.set_native_fn("range", StepFloatRange::new);
|
|
||||||
#[cfg(feature = "metadata")]
|
#[cfg(feature = "metadata")]
|
||||||
lib.update_fn_metadata_with_comments(
|
lib.update_fn_metadata_with_comments(
|
||||||
_hash,
|
_hash,
|
||||||
@ -408,62 +483,9 @@ def_package! {
|
|||||||
|
|
||||||
#[cfg(feature = "decimal")]
|
#[cfg(feature = "decimal")]
|
||||||
{
|
{
|
||||||
use rust_decimal::Decimal;
|
lib.set_iterator::<decimal::StepDecimalRange>();
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
|
let _hash = lib.set_native_fn("range", decimal::StepDecimalRange::new);
|
||||||
struct StepDecimalRange(Decimal, Decimal, Decimal);
|
|
||||||
|
|
||||||
impl StepDecimalRange {
|
|
||||||
pub fn new(from: Decimal, to: Decimal, step: Decimal) -> RhaiResultOf<Self> {
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
|
||||||
if step.is_zero() {
|
|
||||||
return Err(crate::ERR::ErrorInFunctionCall("range".to_string(), "".to_string(),
|
|
||||||
crate::ERR::ErrorArithmetic("step value cannot be zero".to_string(), Position::NONE).into(),
|
|
||||||
Position::NONE,
|
|
||||||
).into());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Self(from, to, step))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Iterator for StepDecimalRange {
|
|
||||||
type Item = Decimal;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Decimal> {
|
|
||||||
if self.0 == self.1 {
|
|
||||||
None
|
|
||||||
} else if self.0 < self.1 {
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
|
||||||
if self.2.is_sign_negative() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let v = self.0;
|
|
||||||
let n = self.0 + self.2;
|
|
||||||
|
|
||||||
self.0 = if n >= self.1 { self.1 } else { n };
|
|
||||||
Some(v)
|
|
||||||
} else {
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
|
||||||
if self.2.is_sign_positive() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let v = self.0;
|
|
||||||
let n = self.0 + self.2;
|
|
||||||
|
|
||||||
self.0 = if n <= self.1 { self.1 } else { n };
|
|
||||||
Some(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FusedIterator for StepDecimalRange {}
|
|
||||||
|
|
||||||
lib.set_iterator::<StepDecimalRange>();
|
|
||||||
|
|
||||||
let _hash = lib.set_native_fn("range", StepDecimalRange::new);
|
|
||||||
#[cfg(feature = "metadata")]
|
#[cfg(feature = "metadata")]
|
||||||
lib.update_fn_metadata_with_comments(
|
lib.update_fn_metadata_with_comments(
|
||||||
_hash,
|
_hash,
|
||||||
@ -773,13 +795,13 @@ mod range_functions {
|
|||||||
/// Return `true` if the range is inclusive.
|
/// Return `true` if the range is inclusive.
|
||||||
#[rhai_fn(get = "is_inclusive", name = "is_inclusive", pure)]
|
#[rhai_fn(get = "is_inclusive", name = "is_inclusive", pure)]
|
||||||
pub fn is_inclusive(range: &mut ExclusiveRange) -> bool {
|
pub fn is_inclusive(range: &mut ExclusiveRange) -> bool {
|
||||||
let _range = range;
|
let _ = range;
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
/// Return `true` if the range is exclusive.
|
/// Return `true` if the range is exclusive.
|
||||||
#[rhai_fn(get = "is_exclusive", name = "is_exclusive", pure)]
|
#[rhai_fn(get = "is_exclusive", name = "is_exclusive", pure)]
|
||||||
pub fn is_exclusive(range: &mut ExclusiveRange) -> bool {
|
pub fn is_exclusive(range: &mut ExclusiveRange) -> bool {
|
||||||
let _range = range;
|
let _ = range;
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
/// Return the start of the inclusive range.
|
/// Return the start of the inclusive range.
|
||||||
@ -795,13 +817,13 @@ mod range_functions {
|
|||||||
/// Return `true` if the range is inclusive.
|
/// Return `true` if the range is inclusive.
|
||||||
#[rhai_fn(get = "is_inclusive", name = "is_inclusive", pure)]
|
#[rhai_fn(get = "is_inclusive", name = "is_inclusive", pure)]
|
||||||
pub fn is_inclusive_inclusive(range: &mut InclusiveRange) -> bool {
|
pub fn is_inclusive_inclusive(range: &mut InclusiveRange) -> bool {
|
||||||
let _range = range;
|
let _ = range;
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
/// Return `true` if the range is exclusive.
|
/// Return `true` if the range is exclusive.
|
||||||
#[rhai_fn(get = "is_exclusive", name = "is_exclusive", pure)]
|
#[rhai_fn(get = "is_exclusive", name = "is_exclusive", pure)]
|
||||||
pub fn is_exclusive_inclusive(range: &mut InclusiveRange) -> bool {
|
pub fn is_exclusive_inclusive(range: &mut InclusiveRange) -> bool {
|
||||||
let _range = range;
|
let _ = range;
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ mod bit_field;
|
|||||||
pub(crate) mod blob_basic;
|
pub(crate) mod blob_basic;
|
||||||
mod debugging;
|
mod debugging;
|
||||||
mod fn_basic;
|
mod fn_basic;
|
||||||
mod iter_basic;
|
pub(crate) mod iter_basic;
|
||||||
mod lang_core;
|
mod lang_core;
|
||||||
mod logic;
|
mod logic;
|
||||||
mod map_basic;
|
mod map_basic;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use crate::plugin::*;
|
use crate::plugin::*;
|
||||||
use crate::{def_package, FnPtr, INT};
|
use crate::{def_package, FnPtr, INT};
|
||||||
|
use std::any::TypeId;
|
||||||
use std::fmt::{Binary, LowerHex, Octal};
|
use std::fmt::{Binary, LowerHex, Octal};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
@ -20,6 +21,12 @@ def_package! {
|
|||||||
|
|
||||||
combine_with_exported_module!(lib, "print_debug", print_debug_functions);
|
combine_with_exported_module!(lib, "print_debug", print_debug_functions);
|
||||||
combine_with_exported_module!(lib, "number_formatting", number_formatting);
|
combine_with_exported_module!(lib, "number_formatting", number_formatting);
|
||||||
|
|
||||||
|
// Register characters iterator
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
lib.set_iter(TypeId::of::<ImmutableString>(), |value| Box::new(
|
||||||
|
value.cast::<ImmutableString>().chars().map(Into::into).collect::<crate::Array>().into_iter()
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ mod string_functions {
|
|||||||
|
|
||||||
#[rhai_fn(name = "+")]
|
#[rhai_fn(name = "+")]
|
||||||
pub fn add_append_unit(string: ImmutableString, item: ()) -> ImmutableString {
|
pub fn add_append_unit(string: ImmutableString, item: ()) -> ImmutableString {
|
||||||
let _item = item;
|
let _ = item;
|
||||||
string
|
string
|
||||||
}
|
}
|
||||||
#[rhai_fn(name = "+")]
|
#[rhai_fn(name = "+")]
|
||||||
@ -1210,22 +1210,6 @@ mod string_functions {
|
|||||||
pub mod arrays {
|
pub mod arrays {
|
||||||
use crate::{Array, ImmutableString};
|
use crate::{Array, ImmutableString};
|
||||||
|
|
||||||
/// Return an array containing all the characters of the string.
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
///
|
|
||||||
/// ```rhai
|
|
||||||
/// let text = "hello";
|
|
||||||
///
|
|
||||||
/// print(text.split()); // prints "['h', 'e', 'l', 'l', 'o']"
|
|
||||||
#[rhai_fn(name = "split")]
|
|
||||||
pub fn chars(string: &str) -> Array {
|
|
||||||
if string.is_empty() {
|
|
||||||
Array::new()
|
|
||||||
} else {
|
|
||||||
string.chars().map(Into::into).collect()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// Split the string into two at the specified `index` position and return it both strings
|
/// Split the string into two at the specified `index` position and return it both strings
|
||||||
/// as an array.
|
/// as an array.
|
||||||
///
|
///
|
||||||
@ -1275,6 +1259,40 @@ mod string_functions {
|
|||||||
vec![prefix.into(), string[prefix_len..].into()]
|
vec![prefix.into(), string[prefix_len..].into()]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// Return an array containing all the characters of the string.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```rhai
|
||||||
|
/// let text = "hello";
|
||||||
|
///
|
||||||
|
/// print(text.to_chars()); // prints "['h', 'e', 'l', 'l', 'o']"
|
||||||
|
/// ```
|
||||||
|
#[rhai_fn(name = "to_chars")]
|
||||||
|
pub fn to_chars(string: &str) -> Array {
|
||||||
|
if string.is_empty() {
|
||||||
|
Array::new()
|
||||||
|
} else {
|
||||||
|
string.chars().map(Into::into).collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Split the string into segments based on whitespaces, returning an array of the segments.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```rhai
|
||||||
|
/// let text = "hello, world! hello, foo!";
|
||||||
|
///
|
||||||
|
/// print(text.split()); // prints ["hello,", "world!", "hello,", "foo!"]
|
||||||
|
/// ```
|
||||||
|
#[rhai_fn(name = "split")]
|
||||||
|
pub fn split_whitespace(string: &str) -> Array {
|
||||||
|
if string.is_empty() {
|
||||||
|
Array::new()
|
||||||
|
} else {
|
||||||
|
string.split_whitespace().map(Into::into).collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
/// Split the string into segments based on a `delimiter` string, returning an array of the segments.
|
/// Split the string into segments based on a `delimiter` string, returning an array of the segments.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
|
@ -316,8 +316,6 @@ impl Expr {
|
|||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
Expr::FloatConstant(..) => "a floating-point number",
|
Expr::FloatConstant(..) => "a floating-point number",
|
||||||
Expr::CharConstant(..) => "a character",
|
Expr::CharConstant(..) => "a character",
|
||||||
Expr::StringConstant(..) => "a string",
|
|
||||||
Expr::InterpolatedString(..) => "a string",
|
|
||||||
Expr::Map(..) => "an object map",
|
Expr::Map(..) => "an object map",
|
||||||
_ => return Ok(self),
|
_ => return Ok(self),
|
||||||
};
|
};
|
||||||
@ -3506,11 +3504,9 @@ impl Engine {
|
|||||||
&self,
|
&self,
|
||||||
input: &mut TokenStream,
|
input: &mut TokenStream,
|
||||||
state: &mut ParseState,
|
state: &mut ParseState,
|
||||||
scope: &Scope,
|
_scope: &Scope,
|
||||||
optimization_level: OptimizationLevel,
|
_optimization_level: OptimizationLevel,
|
||||||
) -> ParseResult<AST> {
|
) -> ParseResult<AST> {
|
||||||
let _scope = scope;
|
|
||||||
let _optimization_level = optimization_level;
|
|
||||||
let mut functions = BTreeMap::new();
|
let mut functions = BTreeMap::new();
|
||||||
|
|
||||||
let settings = ParseSettings {
|
let settings = ParseSettings {
|
||||||
@ -3554,7 +3550,7 @@ impl Engine {
|
|||||||
statements,
|
statements,
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
StaticVec::new_const(),
|
StaticVec::new_const(),
|
||||||
optimization_level,
|
_optimization_level,
|
||||||
));
|
));
|
||||||
|
|
||||||
#[cfg(feature = "no_optimize")]
|
#[cfg(feature = "no_optimize")]
|
||||||
@ -3632,12 +3628,9 @@ impl Engine {
|
|||||||
&self,
|
&self,
|
||||||
input: &mut TokenStream,
|
input: &mut TokenStream,
|
||||||
state: &mut ParseState,
|
state: &mut ParseState,
|
||||||
scope: &Scope,
|
_scope: &Scope,
|
||||||
optimization_level: OptimizationLevel,
|
_optimization_level: OptimizationLevel,
|
||||||
) -> ParseResult<AST> {
|
) -> ParseResult<AST> {
|
||||||
let _scope = scope;
|
|
||||||
let _optimization_level = optimization_level;
|
|
||||||
|
|
||||||
let (statements, _lib) = self.parse_global_level(input, state)?;
|
let (statements, _lib) = self.parse_global_level(input, state)?;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_optimize"))]
|
#[cfg(not(feature = "no_optimize"))]
|
||||||
@ -3647,7 +3640,7 @@ impl Engine {
|
|||||||
statements,
|
statements,
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
_lib,
|
_lib,
|
||||||
optimization_level,
|
_optimization_level,
|
||||||
));
|
));
|
||||||
|
|
||||||
#[cfg(feature = "no_optimize")]
|
#[cfg(feature = "no_optimize")]
|
||||||
|
@ -417,9 +417,9 @@ impl SerializeSeq for DynamicSerializer {
|
|||||||
fn serialize_element<T: ?Sized + Serialize>(&mut self, _value: &T) -> RhaiResultOf<()> {
|
fn serialize_element<T: ?Sized + Serialize>(&mut self, _value: &T) -> RhaiResultOf<()> {
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
{
|
{
|
||||||
let _value = _value.serialize(&mut *self)?;
|
let value = _value.serialize(&mut *self)?;
|
||||||
let arr = self._value.downcast_mut::<crate::Array>().unwrap();
|
let arr = self._value.downcast_mut::<crate::Array>().unwrap();
|
||||||
arr.push(_value);
|
arr.push(value);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
#[cfg(feature = "no_index")]
|
#[cfg(feature = "no_index")]
|
||||||
@ -452,9 +452,9 @@ impl SerializeTuple for DynamicSerializer {
|
|||||||
fn serialize_element<T: ?Sized + Serialize>(&mut self, _value: &T) -> RhaiResultOf<()> {
|
fn serialize_element<T: ?Sized + Serialize>(&mut self, _value: &T) -> RhaiResultOf<()> {
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
{
|
{
|
||||||
let _value = _value.serialize(&mut *self)?;
|
let value = _value.serialize(&mut *self)?;
|
||||||
let arr = self._value.downcast_mut::<crate::Array>().unwrap();
|
let arr = self._value.downcast_mut::<crate::Array>().unwrap();
|
||||||
arr.push(_value);
|
arr.push(value);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
#[cfg(feature = "no_index")]
|
#[cfg(feature = "no_index")]
|
||||||
@ -486,9 +486,9 @@ impl SerializeTupleStruct for DynamicSerializer {
|
|||||||
fn serialize_field<T: ?Sized + Serialize>(&mut self, _value: &T) -> RhaiResultOf<()> {
|
fn serialize_field<T: ?Sized + Serialize>(&mut self, _value: &T) -> RhaiResultOf<()> {
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
{
|
{
|
||||||
let _value = _value.serialize(&mut *self)?;
|
let value = _value.serialize(&mut *self)?;
|
||||||
let arr = self._value.downcast_mut::<crate::Array>().unwrap();
|
let arr = self._value.downcast_mut::<crate::Array>().unwrap();
|
||||||
arr.push(_value);
|
arr.push(value);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
#[cfg(feature = "no_index")]
|
#[cfg(feature = "no_index")]
|
||||||
@ -540,9 +540,9 @@ impl SerializeMap for DynamicSerializer {
|
|||||||
.map_err(|typ| {
|
.map_err(|typ| {
|
||||||
ERR::ErrorMismatchDataType("string".into(), typ.into(), Position::NONE)
|
ERR::ErrorMismatchDataType("string".into(), typ.into(), Position::NONE)
|
||||||
})?;
|
})?;
|
||||||
let _value = _value.serialize(&mut *self)?;
|
let value = _value.serialize(&mut *self)?;
|
||||||
let map = self._value.downcast_mut::<crate::Map>().unwrap();
|
let map = self._value.downcast_mut::<crate::Map>().unwrap();
|
||||||
map.insert(key.into(), _value);
|
map.insert(key.into(), value);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
#[cfg(feature = "no_object")]
|
#[cfg(feature = "no_object")]
|
||||||
@ -561,13 +561,13 @@ impl SerializeMap for DynamicSerializer {
|
|||||||
) -> RhaiResultOf<()> {
|
) -> RhaiResultOf<()> {
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
{
|
{
|
||||||
let _key: Dynamic = _key.serialize(&mut *self)?;
|
let key: Dynamic = _key.serialize(&mut *self)?;
|
||||||
let _key = _key.into_immutable_string().map_err(|typ| {
|
let key = key.into_immutable_string().map_err(|typ| {
|
||||||
ERR::ErrorMismatchDataType("string".into(), typ.into(), Position::NONE)
|
ERR::ErrorMismatchDataType("string".into(), typ.into(), Position::NONE)
|
||||||
})?;
|
})?;
|
||||||
let _value = _value.serialize(&mut *self)?;
|
let value = _value.serialize(&mut *self)?;
|
||||||
let map = self._value.downcast_mut::<crate::Map>().unwrap();
|
let map = self._value.downcast_mut::<crate::Map>().unwrap();
|
||||||
map.insert(_key.into(), _value);
|
map.insert(key.into(), value);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
#[cfg(feature = "no_object")]
|
#[cfg(feature = "no_object")]
|
||||||
@ -603,9 +603,9 @@ impl SerializeStruct for DynamicSerializer {
|
|||||||
) -> RhaiResultOf<()> {
|
) -> RhaiResultOf<()> {
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
{
|
{
|
||||||
let _value = _value.serialize(&mut *self)?;
|
let value = _value.serialize(&mut *self)?;
|
||||||
let map = self._value.downcast_mut::<crate::Map>().unwrap();
|
let map = self._value.downcast_mut::<crate::Map>().unwrap();
|
||||||
map.insert(_key.into(), _value);
|
map.insert(_key.into(), value);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
#[cfg(feature = "no_object")]
|
#[cfg(feature = "no_object")]
|
||||||
|
@ -469,9 +469,7 @@ impl Hash for Dynamic {
|
|||||||
#[cfg(feature = "sync")]
|
#[cfg(feature = "sync")]
|
||||||
Union::Shared(ref cell, ..) => (*cell.read().unwrap()).hash(state),
|
Union::Shared(ref cell, ..) => (*cell.read().unwrap()).hash(state),
|
||||||
|
|
||||||
Union::Variant(ref v, ..) => {
|
Union::Variant(ref _v, ..) => {
|
||||||
let _v = v;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "only_i32"))]
|
#[cfg(not(feature = "only_i32"))]
|
||||||
#[cfg(not(feature = "only_i64"))]
|
#[cfg(not(feature = "only_i64"))]
|
||||||
{
|
{
|
||||||
|
@ -562,3 +562,29 @@ fn test_module_environ() -> Result<(), Box<EvalAltResult>> {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_module_dynamic() -> Result<(), Box<EvalAltResult>> {
|
||||||
|
fn test_fn(input: Dynamic, x: INT) -> Result<INT, Box<EvalAltResult>> {
|
||||||
|
let s = input.into_string().unwrap();
|
||||||
|
Ok(s.len() as INT + x)
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut engine = rhai::Engine::new();
|
||||||
|
let mut module = Module::new();
|
||||||
|
module.set_native_fn("test", test_fn);
|
||||||
|
|
||||||
|
let mut static_modules = rhai::module_resolvers::StaticModuleResolver::new();
|
||||||
|
static_modules.insert("test", module);
|
||||||
|
engine.set_module_resolver(static_modules);
|
||||||
|
engine.register_result_fn("test2", test_fn);
|
||||||
|
|
||||||
|
assert_eq!(engine.eval::<INT>(r#"test2("test", 38);"#)?, 42);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
engine.eval::<INT>(r#"import "test" as test; test::test("test", 38);"#)?,
|
||||||
|
42
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user