commit
1616541df4
28
CHANGELOG.md
28
CHANGELOG.md
@ -1,9 +1,36 @@
|
||||
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
|
||||
=============
|
||||
|
||||
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
|
||||
----------------
|
||||
|
||||
@ -12,6 +39,7 @@ Compiler version
|
||||
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.
|
||||
* `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.
|
||||
|
13
Cargo.toml
13
Cargo.toml
@ -3,7 +3,7 @@ members = [".", "codegen"]
|
||||
|
||||
[package]
|
||||
name = "rhai"
|
||||
version = "1.6.0"
|
||||
version = "1.6.1"
|
||||
rust-version = "1.57"
|
||||
edition = "2018"
|
||||
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 }
|
||||
bitflags = { 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 }
|
||||
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 }
|
||||
unicode-xid = { version = "0.2", default-features = false, 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
|
||||
# this can be moved to the official version when bracketed paste is added
|
||||
rustyline = { version = "9", optional = true, git = "https://github.com/schungx/rustyline" }
|
||||
rustyline = { version = "9", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
serde_bytes = "0.11"
|
||||
@ -91,3 +89,8 @@ instant = { version = "0.1.10" } # WASM implementation of std::time::Instant
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
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
|
||||
=================================
|
||||
==================================
|
||||
|
||||
![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)
|
||||
@ -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)
|
||||
[![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)
|
||||
[![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)
|
||||
[![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
|
||||
---------------------------------------------
|
||||
----------------------------------------------
|
||||
|
||||
* 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).
|
||||
|
@ -12,3 +12,7 @@ note: required by a bound in `rhai::Dynamic::cast`
|
||||
| pub fn cast<T: Any + Clone>(self) -> T {
|
||||
| ^^^^^ 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)
|
||||
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 {
|
||||
| ^^^^^ 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)
|
||||
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 {
|
||||
| ^^^^^ 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)
|
||||
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 {
|
||||
| ^^^^^ 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)
|
||||
help: consider annotating `NonClonable` with `#[derive(Clone)]`
|
||||
|
|
||||
3 | #[derive(Clone)]
|
||||
|
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::packages::iter_basic::{BitRange, CharsStream, StepRange};
|
||||
use crate::{
|
||||
Engine, ExclusiveRange, FnPtr, ImmutableString, InclusiveRange, Position, RhaiError, ERR,
|
||||
};
|
||||
@ -65,6 +66,41 @@ fn map_std_type_name(name: &str, shorthands: bool) -> &str {
|
||||
"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::") {
|
||||
map_std_type_name(&name[6..], shorthands)
|
||||
|
@ -636,9 +636,7 @@ impl Expr {
|
||||
/// `non_qualified` is ignored under `no_module`.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub(crate) fn is_variable_access(&self, non_qualified: bool) -> bool {
|
||||
let _non_qualified = non_qualified;
|
||||
|
||||
pub(crate) fn is_variable_access(&self, _non_qualified: bool) -> bool {
|
||||
match self {
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
Self::Variable(x, ..) if _non_qualified && !x.1.is_empty() => false,
|
||||
@ -651,9 +649,7 @@ impl Expr {
|
||||
/// `non_qualified` is ignored under `no_module`.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub(crate) fn get_variable_name(&self, non_qualified: bool) -> Option<&str> {
|
||||
let _non_qualified = non_qualified;
|
||||
|
||||
pub(crate) fn get_variable_name(&self, _non_qualified: bool) -> Option<&str> {
|
||||
match self {
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
Self::Variable(x, ..) if _non_qualified && !x.1.is_empty() => None,
|
||||
|
@ -321,7 +321,7 @@ fn debug_callback(
|
||||
let mut input = String::new();
|
||||
|
||||
loop {
|
||||
print!("rhai-dbg> ");
|
||||
print!("dbg> ");
|
||||
|
||||
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::error::ReadlineError;
|
||||
use rustyline::{Cmd, Editor, Event, EventHandler, KeyCode, KeyEvent, Modifiers, Movement};
|
||||
use smallvec::smallvec;
|
||||
|
||||
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
|
||||
#[cfg(target_family = "windows")]
|
||||
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)),
|
||||
);
|
||||
// On Windows, Ctrl-Z is undo
|
||||
#[cfg(target_family = "windows")]
|
||||
rl.bind_sequence(
|
||||
Event::KeySeq(smallvec![KeyEvent::ctrl('z')]),
|
||||
Event::KeySeq(vec![KeyEvent::ctrl('z')]),
|
||||
EventHandler::Simple(Cmd::Undo(1)),
|
||||
);
|
||||
// Map Ctrl-Enter to insert a new line - bypass need for `\` continuation
|
||||
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),
|
||||
);
|
||||
rl.bind_sequence(
|
||||
Event::KeySeq(smallvec![KeyEvent(KeyCode::Enter, Modifiers::CTRL)]),
|
||||
Event::KeySeq(vec![KeyEvent(KeyCode::Enter, Modifiers::CTRL)]),
|
||||
EventHandler::Simple(Cmd::Newline),
|
||||
);
|
||||
// Map Ctrl-Home and Ctrl-End for beginning/end of input
|
||||
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)),
|
||||
);
|
||||
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)),
|
||||
);
|
||||
// Map Ctrl-Up and Ctrl-Down to skip up/down the history, even through multi-line histories
|
||||
rl.bind_sequence(
|
||||
Event::KeySeq(smallvec![KeyEvent(KeyCode::Down, Modifiers::CTRL)]),
|
||||
Event::KeySeq(vec![KeyEvent(KeyCode::Down, Modifiers::CTRL)]),
|
||||
EventHandler::Simple(Cmd::NextHistory),
|
||||
);
|
||||
rl.bind_sequence(
|
||||
Event::KeySeq(smallvec![KeyEvent(KeyCode::Up, Modifiers::CTRL)]),
|
||||
Event::KeySeq(vec![KeyEvent(KeyCode::Up, Modifiers::CTRL)]),
|
||||
EventHandler::Simple(Cmd::PreviousHistory),
|
||||
);
|
||||
|
||||
@ -371,11 +370,7 @@ fn main() {
|
||||
input.clear();
|
||||
|
||||
loop {
|
||||
let prompt = if input.is_empty() {
|
||||
"rhai-repl> "
|
||||
} else {
|
||||
" > "
|
||||
};
|
||||
let prompt = if input.is_empty() { "repl> " } else { " > " };
|
||||
|
||||
match rl.readline(prompt) {
|
||||
// Line continuation
|
||||
|
@ -295,9 +295,7 @@ impl Engine {
|
||||
}
|
||||
|
||||
/// Check a result to ensure that it is valid.
|
||||
pub(crate) fn check_return_value(&self, mut result: RhaiResult, pos: Position) -> RhaiResult {
|
||||
let _pos = pos;
|
||||
|
||||
pub(crate) fn check_return_value(&self, mut result: RhaiResult, _pos: Position) -> RhaiResult {
|
||||
match result {
|
||||
Ok(ref mut r) => {
|
||||
// Concentrate all empty strings into one instance to save memory
|
||||
|
@ -127,16 +127,14 @@ impl Engine {
|
||||
this_ptr: &mut Option<&mut Dynamic>,
|
||||
target: &mut Target,
|
||||
root: (&str, Position),
|
||||
parent: &Expr,
|
||||
_parent: &Expr,
|
||||
rhs: &Expr,
|
||||
parent_options: ASTFlags,
|
||||
_parent_options: ASTFlags,
|
||||
idx_values: &mut StaticVec<super::ChainArgument>,
|
||||
chain_type: ChainType,
|
||||
level: usize,
|
||||
new_val: Option<((Dynamic, Position), (Option<OpAssignment>, Position))>,
|
||||
) -> RhaiResultOf<(Dynamic, bool)> {
|
||||
let _parent = parent;
|
||||
let _parent_options = parent_options;
|
||||
let is_ref_mut = target.is_ref();
|
||||
|
||||
// Pop the last index value
|
||||
@ -671,7 +669,7 @@ impl Engine {
|
||||
this_ptr: &mut Option<&mut Dynamic>,
|
||||
expr: &Expr,
|
||||
parent_options: ASTFlags,
|
||||
parent_chain_type: ChainType,
|
||||
_parent_chain_type: ChainType,
|
||||
idx_values: &mut StaticVec<super::ChainArgument>,
|
||||
size: usize,
|
||||
level: usize,
|
||||
@ -679,8 +677,6 @@ impl Engine {
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
self.inc_operations(&mut global.num_operations, expr.position())?;
|
||||
|
||||
let _parent_chain_type = parent_chain_type;
|
||||
|
||||
match expr {
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
Expr::MethodCall(x, ..)
|
||||
@ -850,18 +846,15 @@ impl Engine {
|
||||
state: &mut EvalState,
|
||||
lib: &[&Module],
|
||||
target: &'t mut Dynamic,
|
||||
idx: Dynamic,
|
||||
mut idx: Dynamic,
|
||||
idx_pos: Position,
|
||||
add_if_not_found: bool,
|
||||
_add_if_not_found: bool,
|
||||
use_indexers: bool,
|
||||
level: usize,
|
||||
) -> RhaiResultOf<Target<'t>> {
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
self.inc_operations(&mut global.num_operations, Position::NONE)?;
|
||||
|
||||
let mut idx = idx;
|
||||
let _add_if_not_found = add_if_not_found;
|
||||
|
||||
match target {
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
Dynamic(Union::Array(arr, ..)) => {
|
||||
|
@ -16,9 +16,7 @@ impl Engine {
|
||||
///
|
||||
/// Panics if any interior data is shared (should never happen).
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
pub(crate) fn calc_data_sizes(value: &Dynamic, top: bool) -> (usize, usize, usize) {
|
||||
let _top = top;
|
||||
|
||||
pub(crate) fn calc_data_sizes(value: &Dynamic, _top: bool) -> (usize, usize, usize) {
|
||||
match value.0 {
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
Union::Array(ref arr, ..) => {
|
||||
|
@ -195,7 +195,7 @@ impl Engine {
|
||||
#[must_use]
|
||||
fn resolve_fn<'s>(
|
||||
&self,
|
||||
global: &GlobalRuntimeState,
|
||||
_global: &GlobalRuntimeState,
|
||||
state: &'s mut EvalState,
|
||||
lib: &[&Module],
|
||||
fn_name: &str,
|
||||
@ -204,8 +204,6 @@ impl Engine {
|
||||
allow_dynamic: bool,
|
||||
is_op_assignment: bool,
|
||||
) -> Option<&'s FnResolutionCacheEntry> {
|
||||
let _global = global;
|
||||
|
||||
if hash_script == 0 {
|
||||
return None;
|
||||
}
|
||||
@ -576,7 +574,7 @@ impl Engine {
|
||||
/// all others are silently replaced by `()`!
|
||||
pub(crate) fn exec_fn_call(
|
||||
&self,
|
||||
scope: Option<&mut Scope>,
|
||||
_scope: Option<&mut Scope>,
|
||||
global: &mut GlobalRuntimeState,
|
||||
state: &mut EvalState,
|
||||
lib: &[&Module],
|
||||
@ -584,7 +582,7 @@ impl Engine {
|
||||
hashes: FnCallHashes,
|
||||
args: &mut FnCallArgs,
|
||||
is_ref_mut: bool,
|
||||
is_method_call: bool,
|
||||
_is_method_call: bool,
|
||||
pos: Position,
|
||||
level: usize,
|
||||
) -> RhaiResultOf<(Dynamic, bool)> {
|
||||
@ -600,9 +598,6 @@ impl Engine {
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
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.
|
||||
match fn_name {
|
||||
// Handle type_of()
|
||||
@ -1301,13 +1296,14 @@ impl Engine {
|
||||
}
|
||||
}
|
||||
|
||||
// Search for the root namespace
|
||||
let module = self
|
||||
.search_imports(global, state, namespace)
|
||||
.ok_or_else(|| ERR::ErrorModuleNotFound(namespace.to_string(), namespace.position()))?;
|
||||
|
||||
// First search in script-defined functions (can override built-in)
|
||||
let func = match module.get_qualified_fn(hash) {
|
||||
// Then search in Rust functions
|
||||
// First search script-defined functions in namespace (can override built-in)
|
||||
let mut func = match module.get_qualified_fn(hash) {
|
||||
// Then search native Rust functions
|
||||
None => {
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
self.inc_operations(&mut global.num_operations, pos)?;
|
||||
@ -1320,6 +1316,41 @@ impl Engine {
|
||||
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
|
||||
if !func.map(|f| f.is_method()).unwrap_or(true) {
|
||||
if let Some(first) = first_arg_value {
|
||||
@ -1382,11 +1413,9 @@ impl Engine {
|
||||
state: &mut EvalState,
|
||||
lib: &[&Module],
|
||||
script: &str,
|
||||
pos: Position,
|
||||
_pos: Position,
|
||||
level: usize,
|
||||
) -> RhaiResult {
|
||||
let _pos = pos;
|
||||
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
self.inc_operations(&mut global.num_operations, _pos)?;
|
||||
|
||||
|
@ -38,13 +38,11 @@ impl Engine {
|
||||
#[inline(never)]
|
||||
fn make_error(
|
||||
name: String,
|
||||
fn_def: &ScriptFnDef,
|
||||
_fn_def: &ScriptFnDef,
|
||||
global: &GlobalRuntimeState,
|
||||
err: RhaiError,
|
||||
pos: Position,
|
||||
) -> RhaiResult {
|
||||
let _fn_def = fn_def;
|
||||
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
let source = _fn_def
|
||||
.environ
|
||||
@ -232,13 +230,11 @@ impl Engine {
|
||||
#[must_use]
|
||||
pub(crate) fn has_script_fn(
|
||||
&self,
|
||||
global: Option<&GlobalRuntimeState>,
|
||||
_global: Option<&GlobalRuntimeState>,
|
||||
state: &mut EvalState,
|
||||
lib: &[&Module],
|
||||
hash_script: u64,
|
||||
) -> bool {
|
||||
let _global = global;
|
||||
|
||||
let cache = state.fn_resolution_cache_mut();
|
||||
|
||||
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.
|
||||
///
|
||||
/// # 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)]
|
||||
pub fn set_custom_type<T>(&mut self, name: &str) {
|
||||
self.custom_types.add_type::<T>(name)
|
||||
pub fn set_custom_type<T>(&mut self, name: &str) -> &mut Self {
|
||||
self.custom_types.add_type::<T>(name);
|
||||
self
|
||||
}
|
||||
/// 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)]
|
||||
pub fn set_custom_type_raw(
|
||||
&mut self,
|
||||
type_name: impl Into<Identifier>,
|
||||
name: impl Into<Identifier>,
|
||||
) {
|
||||
self.custom_types.add(type_name, name)
|
||||
) -> &mut Self {
|
||||
self.custom_types.add(type_name, name);
|
||||
self
|
||||
}
|
||||
/// 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)]
|
||||
pub fn get_custom_type(&self, key: &str) -> Option<&str> {
|
||||
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].
|
||||
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
|
||||
const DONT_EVAL_KEYWORDS: &[&str] = &[
|
||||
KEYWORD_PRINT, // side effects
|
||||
@ -871,8 +871,6 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, chaining: bool) {
|
||||
KEYWORD_EVAL, // arbitrary scripts
|
||||
];
|
||||
|
||||
let _chaining = chaining;
|
||||
|
||||
match expr {
|
||||
// {}
|
||||
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
|
||||
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
|
||||
struct StepRange<T>(T, T, T)
|
||||
pub struct StepRange<T>(T, T, T)
|
||||
where
|
||||
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
|
||||
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
|
||||
struct BitRange(INT, INT, usize);
|
||||
pub struct BitRange(INT, INT, usize);
|
||||
|
||||
impl BitRange {
|
||||
pub fn new(value: INT, from: INT, len: INT) -> RhaiResultOf<Self> {
|
||||
@ -166,7 +166,7 @@ impl ExactSizeIterator for BitRange {
|
||||
|
||||
// String iterator over characters
|
||||
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
|
||||
struct CharsStream(Vec<char>, usize);
|
||||
pub struct CharsStream(Vec<char>, usize);
|
||||
|
||||
impl CharsStream {
|
||||
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 {
|
||||
($lib:ident | $x:expr => $( $y:ty ),*) => {
|
||||
$(
|
||||
@ -326,62 +454,9 @@ def_package! {
|
||||
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
{
|
||||
use crate::FLOAT;
|
||||
lib.set_iterator::<float::StepFloatRange>();
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
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);
|
||||
let _hash = lib.set_native_fn("range", float::StepFloatRange::new);
|
||||
#[cfg(feature = "metadata")]
|
||||
lib.update_fn_metadata_with_comments(
|
||||
_hash,
|
||||
@ -408,62 +483,9 @@ def_package! {
|
||||
|
||||
#[cfg(feature = "decimal")]
|
||||
{
|
||||
use rust_decimal::Decimal;
|
||||
lib.set_iterator::<decimal::StepDecimalRange>();
|
||||
|
||||
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
|
||||
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);
|
||||
let _hash = lib.set_native_fn("range", decimal::StepDecimalRange::new);
|
||||
#[cfg(feature = "metadata")]
|
||||
lib.update_fn_metadata_with_comments(
|
||||
_hash,
|
||||
@ -773,13 +795,13 @@ mod range_functions {
|
||||
/// Return `true` if the range is inclusive.
|
||||
#[rhai_fn(get = "is_inclusive", name = "is_inclusive", pure)]
|
||||
pub fn is_inclusive(range: &mut ExclusiveRange) -> bool {
|
||||
let _range = range;
|
||||
let _ = range;
|
||||
false
|
||||
}
|
||||
/// Return `true` if the range is exclusive.
|
||||
#[rhai_fn(get = "is_exclusive", name = "is_exclusive", pure)]
|
||||
pub fn is_exclusive(range: &mut ExclusiveRange) -> bool {
|
||||
let _range = range;
|
||||
let _ = range;
|
||||
true
|
||||
}
|
||||
/// Return the start of the inclusive range.
|
||||
@ -795,13 +817,13 @@ mod range_functions {
|
||||
/// Return `true` if the range is inclusive.
|
||||
#[rhai_fn(get = "is_inclusive", name = "is_inclusive", pure)]
|
||||
pub fn is_inclusive_inclusive(range: &mut InclusiveRange) -> bool {
|
||||
let _range = range;
|
||||
let _ = range;
|
||||
true
|
||||
}
|
||||
/// Return `true` if the range is exclusive.
|
||||
#[rhai_fn(get = "is_exclusive", name = "is_exclusive", pure)]
|
||||
pub fn is_exclusive_inclusive(range: &mut InclusiveRange) -> bool {
|
||||
let _range = range;
|
||||
let _ = range;
|
||||
false
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ mod bit_field;
|
||||
pub(crate) mod blob_basic;
|
||||
mod debugging;
|
||||
mod fn_basic;
|
||||
mod iter_basic;
|
||||
pub(crate) mod iter_basic;
|
||||
mod lang_core;
|
||||
mod logic;
|
||||
mod map_basic;
|
||||
|
@ -1,5 +1,6 @@
|
||||
use crate::plugin::*;
|
||||
use crate::{def_package, FnPtr, INT};
|
||||
use std::any::TypeId;
|
||||
use std::fmt::{Binary, LowerHex, Octal};
|
||||
#[cfg(feature = "no_std")]
|
||||
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, "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 = "+")]
|
||||
pub fn add_append_unit(string: ImmutableString, item: ()) -> ImmutableString {
|
||||
let _item = item;
|
||||
let _ = item;
|
||||
string
|
||||
}
|
||||
#[rhai_fn(name = "+")]
|
||||
@ -1210,22 +1210,6 @@ mod string_functions {
|
||||
pub mod arrays {
|
||||
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
|
||||
/// as an array.
|
||||
///
|
||||
@ -1275,6 +1259,40 @@ mod string_functions {
|
||||
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.
|
||||
///
|
||||
/// # Example
|
||||
|
@ -316,8 +316,6 @@ impl Expr {
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
Expr::FloatConstant(..) => "a floating-point number",
|
||||
Expr::CharConstant(..) => "a character",
|
||||
Expr::StringConstant(..) => "a string",
|
||||
Expr::InterpolatedString(..) => "a string",
|
||||
Expr::Map(..) => "an object map",
|
||||
_ => return Ok(self),
|
||||
};
|
||||
@ -3506,11 +3504,9 @@ impl Engine {
|
||||
&self,
|
||||
input: &mut TokenStream,
|
||||
state: &mut ParseState,
|
||||
scope: &Scope,
|
||||
optimization_level: OptimizationLevel,
|
||||
_scope: &Scope,
|
||||
_optimization_level: OptimizationLevel,
|
||||
) -> ParseResult<AST> {
|
||||
let _scope = scope;
|
||||
let _optimization_level = optimization_level;
|
||||
let mut functions = BTreeMap::new();
|
||||
|
||||
let settings = ParseSettings {
|
||||
@ -3554,7 +3550,7 @@ impl Engine {
|
||||
statements,
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
StaticVec::new_const(),
|
||||
optimization_level,
|
||||
_optimization_level,
|
||||
));
|
||||
|
||||
#[cfg(feature = "no_optimize")]
|
||||
@ -3632,12 +3628,9 @@ impl Engine {
|
||||
&self,
|
||||
input: &mut TokenStream,
|
||||
state: &mut ParseState,
|
||||
scope: &Scope,
|
||||
optimization_level: OptimizationLevel,
|
||||
_scope: &Scope,
|
||||
_optimization_level: OptimizationLevel,
|
||||
) -> ParseResult<AST> {
|
||||
let _scope = scope;
|
||||
let _optimization_level = optimization_level;
|
||||
|
||||
let (statements, _lib) = self.parse_global_level(input, state)?;
|
||||
|
||||
#[cfg(not(feature = "no_optimize"))]
|
||||
@ -3647,7 +3640,7 @@ impl Engine {
|
||||
statements,
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
_lib,
|
||||
optimization_level,
|
||||
_optimization_level,
|
||||
));
|
||||
|
||||
#[cfg(feature = "no_optimize")]
|
||||
|
@ -417,9 +417,9 @@ impl SerializeSeq for DynamicSerializer {
|
||||
fn serialize_element<T: ?Sized + Serialize>(&mut self, _value: &T) -> RhaiResultOf<()> {
|
||||
#[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();
|
||||
arr.push(_value);
|
||||
arr.push(value);
|
||||
Ok(())
|
||||
}
|
||||
#[cfg(feature = "no_index")]
|
||||
@ -452,9 +452,9 @@ impl SerializeTuple for DynamicSerializer {
|
||||
fn serialize_element<T: ?Sized + Serialize>(&mut self, _value: &T) -> RhaiResultOf<()> {
|
||||
#[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();
|
||||
arr.push(_value);
|
||||
arr.push(value);
|
||||
Ok(())
|
||||
}
|
||||
#[cfg(feature = "no_index")]
|
||||
@ -486,9 +486,9 @@ impl SerializeTupleStruct for DynamicSerializer {
|
||||
fn serialize_field<T: ?Sized + Serialize>(&mut self, _value: &T) -> RhaiResultOf<()> {
|
||||
#[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();
|
||||
arr.push(_value);
|
||||
arr.push(value);
|
||||
Ok(())
|
||||
}
|
||||
#[cfg(feature = "no_index")]
|
||||
@ -540,9 +540,9 @@ impl SerializeMap for DynamicSerializer {
|
||||
.map_err(|typ| {
|
||||
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();
|
||||
map.insert(key.into(), _value);
|
||||
map.insert(key.into(), value);
|
||||
Ok(())
|
||||
}
|
||||
#[cfg(feature = "no_object")]
|
||||
@ -561,13 +561,13 @@ impl SerializeMap for DynamicSerializer {
|
||||
) -> RhaiResultOf<()> {
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
{
|
||||
let _key: Dynamic = _key.serialize(&mut *self)?;
|
||||
let _key = _key.into_immutable_string().map_err(|typ| {
|
||||
let key: Dynamic = _key.serialize(&mut *self)?;
|
||||
let key = key.into_immutable_string().map_err(|typ| {
|
||||
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();
|
||||
map.insert(_key.into(), _value);
|
||||
map.insert(key.into(), value);
|
||||
Ok(())
|
||||
}
|
||||
#[cfg(feature = "no_object")]
|
||||
@ -603,9 +603,9 @@ impl SerializeStruct for DynamicSerializer {
|
||||
) -> RhaiResultOf<()> {
|
||||
#[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();
|
||||
map.insert(_key.into(), _value);
|
||||
map.insert(_key.into(), value);
|
||||
Ok(())
|
||||
}
|
||||
#[cfg(feature = "no_object")]
|
||||
|
@ -469,9 +469,7 @@ impl Hash for Dynamic {
|
||||
#[cfg(feature = "sync")]
|
||||
Union::Shared(ref cell, ..) => (*cell.read().unwrap()).hash(state),
|
||||
|
||||
Union::Variant(ref v, ..) => {
|
||||
let _v = v;
|
||||
|
||||
Union::Variant(ref _v, ..) => {
|
||||
#[cfg(not(feature = "only_i32"))]
|
||||
#[cfg(not(feature = "only_i64"))]
|
||||
{
|
||||
|
@ -562,3 +562,29 @@ fn test_module_environ() -> Result<(), Box<EvalAltResult>> {
|
||||
|
||||
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