Merge pull request #335 from schungx/master
Fix plugin function argument bug.
This commit is contained in:
commit
d2908384c2
@ -24,7 +24,7 @@ categories = [ "no-std", "embedded", "wasm", "parser-implementations" ]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
smallvec = { version = "1.6", default-features = false, features = ["union"] }
|
smallvec = { version = "1.6", default-features = false, features = ["union"] }
|
||||||
ahash = { version = "0.5", default-features = false }
|
ahash = { version = "0.6", default-features = false }
|
||||||
rhai_codegen = { version = "0.3", path = "codegen" }
|
rhai_codegen = { version = "0.3", path = "codegen" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
10
README.md
10
README.md
@ -28,22 +28,22 @@ Supported targets and builds
|
|||||||
Standard features
|
Standard features
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
* Easy-to-use language similar to JavaScript+Rust with dynamic typing.
|
* Simple language similar to JavaScript+Rust with dynamic typing.
|
||||||
* Fairly low compile-time overhead.
|
* Fairly efficient evaluation (1 million iterations in 0.3 sec on a single-core, 2.3 GHz Linux VM).
|
||||||
* Fairly efficient evaluation (1 million iterations in 0.3 sec on a single core, 2.3 GHz Linux VM).
|
|
||||||
* Tight integration with native Rust [functions](https://rhaiscript.github.io/book/rust/functions.html) and [types]([#custom-types-and-methods](https://rhaiscript.github.io/book/rust/custom.html)), including [getters/setters](https://rhaiscript.github.io/book/rust/getters-setters.html), [methods](https://rhaiscript.github.io/book/rust/custom.html) and [indexers](https://rhaiscript.github.io/book/rust/indexers.html).
|
* Tight integration with native Rust [functions](https://rhaiscript.github.io/book/rust/functions.html) and [types]([#custom-types-and-methods](https://rhaiscript.github.io/book/rust/custom.html)), including [getters/setters](https://rhaiscript.github.io/book/rust/getters-setters.html), [methods](https://rhaiscript.github.io/book/rust/custom.html) and [indexers](https://rhaiscript.github.io/book/rust/indexers.html).
|
||||||
* Freely pass Rust variables/constants into a script via an external [`Scope`](https://rhaiscript.github.io/book/rust/scope.html) - all clonable Rust types are supported; no need to implement any special trait.
|
* Freely pass Rust variables/constants into a script via an external [`Scope`](https://rhaiscript.github.io/book/rust/scope.html) - all clonable Rust types are supported; no need to implement any special trait.
|
||||||
* Easily [call a script-defined function](https://rhaiscript.github.io/book/engine/call-fn.html) from Rust.
|
* Easily [call a script-defined function](https://rhaiscript.github.io/book/engine/call-fn.html) from Rust.
|
||||||
* Relatively little `unsafe` code (yes there are some for performance reasons).
|
* Relatively little `unsafe` code (yes there are some for performance reasons).
|
||||||
* Few dependencies (currently only [`smallvec`](https://crates.io/crates/smallvec) and [`ahash`](https://crates.io/crates/ahash)).
|
* Few dependencies (currently only [`smallvec`](https://crates.io/crates/smallvec) and [`ahash`](https://crates.io/crates/ahash)).
|
||||||
* Re-entrant scripting engine can be made `Send + Sync` (via the `sync` feature).
|
* Re-entrant scripting engine can be made `Send + Sync` (via the `sync` feature).
|
||||||
* Scripts are [optimized](https://rhaiscript.github.io/book/engine/optimize.html) (useful for template-based machine-generated scripts) for repeated evaluations.
|
* Compile once to AST form for repeated evaluations.
|
||||||
|
* Scripts are [optimized](https://rhaiscript.github.io/book/engine/optimize.html) (useful for template-based machine-generated scripts).
|
||||||
* Easy custom API development via [plugins](https://rhaiscript.github.io/book/plugins/index.html) system powered by procedural macros.
|
* Easy custom API development via [plugins](https://rhaiscript.github.io/book/plugins/index.html) system powered by procedural macros.
|
||||||
* [Function overloading](https://rhaiscript.github.io/book/language/overload.html) and [operator overloading](https://rhaiscript.github.io/book/rust/operators.html).
|
* [Function overloading](https://rhaiscript.github.io/book/language/overload.html) and [operator overloading](https://rhaiscript.github.io/book/rust/operators.html).
|
||||||
* Dynamic dispatch via [function pointers](https://rhaiscript.github.io/book/language/fn-ptr.html) with additional support for [currying](https://rhaiscript.github.io/book/language/fn-curry.html).
|
* Dynamic dispatch via [function pointers](https://rhaiscript.github.io/book/language/fn-ptr.html) with additional support for [currying](https://rhaiscript.github.io/book/language/fn-curry.html).
|
||||||
* [Closures](https://rhaiscript.github.io/book/language/fn-closure.html) (anonymous functions) that can capture shared values.
|
* [Closures](https://rhaiscript.github.io/book/language/fn-closure.html) (anonymous functions) that can capture shared values.
|
||||||
* Some syntactic support for [object-oriented programming (OOP)](https://rhaiscript.github.io/book/language/oop.html).
|
* Some syntactic support for [object-oriented programming (OOP)](https://rhaiscript.github.io/book/language/oop.html).
|
||||||
* Organize code base with dynamically-loadable [modules](https://rhaiscript.github.io/book/language/modules.html).
|
* Organize code base with dynamically-loadable [modules](https://rhaiscript.github.io/book/language/modules.html), optionally overriding the resolution process
|
||||||
* Serialization/deserialization support via [serde](https://crates.io/crates/serde) (requires the `serde` feature).
|
* Serialization/deserialization support via [serde](https://crates.io/crates/serde) (requires the `serde` feature).
|
||||||
* Support for [minimal builds](https://rhaiscript.github.io/book/start/builds/minimal.html) by excluding unneeded language [features](https://rhaiscript.github.io/book/start/features.html).
|
* Support for [minimal builds](https://rhaiscript.github.io/book/start/builds/minimal.html) by excluding unneeded language [features](https://rhaiscript.github.io/book/start/features.html).
|
||||||
|
|
||||||
|
15
RELEASES.md
15
RELEASES.md
@ -4,20 +4,33 @@ Rhai Release Notes
|
|||||||
Version 0.19.11
|
Version 0.19.11
|
||||||
===============
|
===============
|
||||||
|
|
||||||
|
This version streamlines compiling for WASM.
|
||||||
|
|
||||||
|
Rust compiler minimum version is raised to 1.49.
|
||||||
|
|
||||||
Breaking changes
|
Breaking changes
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
Rust compiler requirement raised to 1.49.
|
* Rust compiler requirement raised to 1.49.
|
||||||
|
* `NativeCallContext::new` taker an additional parameter containing the name of the function called.
|
||||||
|
|
||||||
Bug fixes
|
Bug fixes
|
||||||
---------
|
---------
|
||||||
|
|
||||||
|
* Parameters passed to plugin module functions were sometimes erroneously consumed. This is now fixed.
|
||||||
* Fixes compilation errors in `metadata` feature build.
|
* Fixes compilation errors in `metadata` feature build.
|
||||||
|
|
||||||
|
New features
|
||||||
|
------------
|
||||||
|
|
||||||
|
* Two new features, `wasm-bindgen` and `stdweb`, to specify the JS interop layer for WASM builds. `wasm-bindgen` used to be required.
|
||||||
|
|
||||||
Enhancements
|
Enhancements
|
||||||
------------
|
------------
|
||||||
|
|
||||||
* `ahash` is used to hash function call parameters. This should yield speed improvements.
|
* `ahash` is used to hash function call parameters. This should yield speed improvements.
|
||||||
|
* `Dynamic` and `ImmutableString` now implement `serde::Serialize` and `serde::Deserialize`.
|
||||||
|
* `NativeCallContext` has a new field containing the name of the function called, useful when the same Rust function is registered under multiple names in Rhai.
|
||||||
|
|
||||||
|
|
||||||
Version 0.19.10
|
Version 0.19.10
|
||||||
|
@ -1971,12 +1971,16 @@ impl Engine {
|
|||||||
let args = &mut [lhs_ptr_inner, &mut rhs_val];
|
let args = &mut [lhs_ptr_inner, &mut rhs_val];
|
||||||
|
|
||||||
// Overriding exact implementation
|
// Overriding exact implementation
|
||||||
let source = source.or_else(|| state.source.as_ref());
|
let source =
|
||||||
|
source.or_else(|| state.source.as_ref()).map(|s| s.as_str());
|
||||||
if func.is_plugin_fn() {
|
if func.is_plugin_fn() {
|
||||||
func.get_plugin_fn()
|
func.get_plugin_fn()
|
||||||
.call((self, source, &*mods, lib).into(), args)?;
|
.call((self, op.as_ref(), source, &*mods, lib).into(), args)?;
|
||||||
} else {
|
} else {
|
||||||
func.get_native_fn()((self, source, &*mods, lib).into(), args)?;
|
func.get_native_fn()(
|
||||||
|
(self, op.as_ref(), source, &*mods, lib).into(),
|
||||||
|
args,
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Built-in op-assignment function
|
// Built-in op-assignment function
|
||||||
|
@ -211,12 +211,13 @@ impl Engine {
|
|||||||
state.source.as_ref()
|
state.source.as_ref()
|
||||||
} else {
|
} else {
|
||||||
source.as_ref()
|
source.as_ref()
|
||||||
};
|
}
|
||||||
|
.map(|s| s.as_str());
|
||||||
let result = if func.is_plugin_fn() {
|
let result = if func.is_plugin_fn() {
|
||||||
func.get_plugin_fn()
|
func.get_plugin_fn()
|
||||||
.call((self, source, mods, lib).into(), args)
|
.call((self, fn_name, source, mods, lib).into(), args)
|
||||||
} else {
|
} else {
|
||||||
func.get_native_fn()((self, source, mods, lib).into(), args)
|
func.get_native_fn()((self, fn_name, source, mods, lib).into(), args)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Restore the original reference
|
// Restore the original reference
|
||||||
@ -1209,16 +1210,18 @@ impl Engine {
|
|||||||
r => r,
|
r => r,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Clone first argument if the function is not a method after-all
|
||||||
|
if let Some(first) = first_arg_value {
|
||||||
|
if !func.map(|f| f.is_method()).unwrap_or(true) {
|
||||||
|
let first_val = args[0].clone();
|
||||||
|
args[0] = first;
|
||||||
|
*args[0] = first_val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
match func {
|
match func {
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
Some(f) if f.is_script() => {
|
Some(f) if f.is_script() => {
|
||||||
// Clone first argument
|
|
||||||
if let Some(first) = first_arg_value {
|
|
||||||
let first_val = args[0].clone();
|
|
||||||
args[0] = first;
|
|
||||||
*args[0] = first_val;
|
|
||||||
}
|
|
||||||
|
|
||||||
let args = args.as_mut();
|
let args = args.as_mut();
|
||||||
let new_scope = &mut Default::default();
|
let new_scope = &mut Default::default();
|
||||||
let fn_def = f.get_fn_def().clone();
|
let fn_def = f.get_fn_def().clone();
|
||||||
@ -1236,22 +1239,14 @@ impl Engine {
|
|||||||
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
Some(f) if f.is_plugin_fn() => f
|
Some(f) if f.is_plugin_fn() => f.get_plugin_fn().clone().call(
|
||||||
.get_plugin_fn()
|
(self, fn_name, module.id(), &*mods, lib).into(),
|
||||||
.clone()
|
args.as_mut(),
|
||||||
.call((self, module.id_raw(), &*mods, lib).into(), args.as_mut()),
|
),
|
||||||
Some(f) if f.is_native() => {
|
Some(f) if f.is_native() => f.get_native_fn()(
|
||||||
if !f.is_method() {
|
(self, fn_name, module.id(), &*mods, lib).into(),
|
||||||
// Clone first argument
|
args.as_mut(),
|
||||||
if let Some(first) = first_arg_value {
|
),
|
||||||
let first_val = args[0].clone();
|
|
||||||
args[0] = first;
|
|
||||||
*args[0] = first_val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
f.get_native_fn()((self, module.id_raw(), &*mods, lib).into(), args.as_mut())
|
|
||||||
}
|
|
||||||
Some(f) => unreachable!("unknown function type: {:?}", f),
|
Some(f) => unreachable!("unknown function type: {:?}", f),
|
||||||
None if def_val.is_some() => Ok(def_val.unwrap().clone()),
|
None if def_val.is_some() => Ok(def_val.unwrap().clone()),
|
||||||
None => EvalAltResult::ErrorFunctionNotFound(
|
None => EvalAltResult::ErrorFunctionNotFound(
|
||||||
|
@ -55,48 +55,52 @@ pub type Locked<T> = crate::stdlib::sync::RwLock<T>;
|
|||||||
|
|
||||||
/// Context of a native Rust function call.
|
/// Context of a native Rust function call.
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct NativeCallContext<'e, 's, 'a, 'm, 'pm: 'm> {
|
pub struct NativeCallContext<'e, 'n, 's, 'a, 'm, 'pm: 'm> {
|
||||||
engine: &'e Engine,
|
engine: &'e Engine,
|
||||||
|
fn_name: &'n str,
|
||||||
source: Option<&'s str>,
|
source: Option<&'s str>,
|
||||||
pub(crate) mods: Option<&'a Imports>,
|
pub(crate) mods: Option<&'a Imports>,
|
||||||
pub(crate) lib: &'m [&'pm Module],
|
pub(crate) lib: &'m [&'pm Module],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'e, 's, 'a, 'm, 'pm: 'm, M: AsRef<[&'pm Module]> + ?Sized>
|
impl<'e, 'n, 's, 'a, 'm, 'pm: 'm, M: AsRef<[&'pm Module]> + ?Sized>
|
||||||
From<(&'e Engine, Option<&'s ImmutableString>, &'a Imports, &'m M)>
|
From<(&'e Engine, &'n str, Option<&'s str>, &'a Imports, &'m M)>
|
||||||
for NativeCallContext<'e, 's, 'a, 'm, 'pm>
|
for NativeCallContext<'e, 'n, 's, 'a, 'm, 'pm>
|
||||||
{
|
{
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn from(value: (&'e Engine, Option<&'s ImmutableString>, &'a Imports, &'m M)) -> Self {
|
fn from(value: (&'e Engine, &'n str, Option<&'s str>, &'a Imports, &'m M)) -> Self {
|
||||||
Self {
|
Self {
|
||||||
engine: value.0,
|
engine: value.0,
|
||||||
source: value.1.map(|s| s.as_str()),
|
fn_name: value.1,
|
||||||
mods: Some(value.2),
|
source: value.2,
|
||||||
lib: value.3.as_ref(),
|
mods: Some(value.3),
|
||||||
|
lib: value.4.as_ref(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'e, 'm, 'pm: 'm, M: AsRef<[&'pm Module]> + ?Sized> From<(&'e Engine, &'m M)>
|
impl<'e, 'n, 'm, 'pm: 'm, M: AsRef<[&'pm Module]> + ?Sized> From<(&'e Engine, &'n str, &'m M)>
|
||||||
for NativeCallContext<'e, '_, '_, 'm, 'pm>
|
for NativeCallContext<'e, 'n, '_, '_, 'm, 'pm>
|
||||||
{
|
{
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn from(value: (&'e Engine, &'m M)) -> Self {
|
fn from(value: (&'e Engine, &'n str, &'m M)) -> Self {
|
||||||
Self {
|
Self {
|
||||||
engine: value.0,
|
engine: value.0,
|
||||||
|
fn_name: value.1,
|
||||||
source: None,
|
source: None,
|
||||||
mods: None,
|
mods: None,
|
||||||
lib: value.1.as_ref(),
|
lib: value.2.as_ref(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'e, 's, 'a, 'm, 'pm> NativeCallContext<'e, 's, 'a, 'm, 'pm> {
|
impl<'e, 'n, 's, 'a, 'm, 'pm> NativeCallContext<'e, 'n, 's, 'a, 'm, 'pm> {
|
||||||
/// Create a new [`NativeCallContext`].
|
/// Create a new [`NativeCallContext`].
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn new(engine: &'e Engine, lib: &'m impl AsRef<[&'pm Module]>) -> Self {
|
pub fn new(engine: &'e Engine, fn_name: &'n str, lib: &'m impl AsRef<[&'pm Module]>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
engine,
|
engine,
|
||||||
|
fn_name,
|
||||||
source: None,
|
source: None,
|
||||||
mods: None,
|
mods: None,
|
||||||
lib: lib.as_ref(),
|
lib: lib.as_ref(),
|
||||||
@ -109,13 +113,15 @@ impl<'e, 's, 'a, 'm, 'pm> NativeCallContext<'e, 's, 'a, 'm, 'pm> {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn new_with_all_fields(
|
pub fn new_with_all_fields(
|
||||||
engine: &'e Engine,
|
engine: &'e Engine,
|
||||||
source: &'s Option<ImmutableString>,
|
fn_name: &'n str,
|
||||||
|
source: &'s Option<&str>,
|
||||||
imports: &'a mut Imports,
|
imports: &'a mut Imports,
|
||||||
lib: &'m impl AsRef<[&'pm Module]>,
|
lib: &'m impl AsRef<[&'pm Module]>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
engine,
|
engine,
|
||||||
source: source.as_ref().map(|s| s.as_str()),
|
fn_name,
|
||||||
|
source: source.clone(),
|
||||||
mods: Some(imports),
|
mods: Some(imports),
|
||||||
lib: lib.as_ref(),
|
lib: lib.as_ref(),
|
||||||
}
|
}
|
||||||
@ -125,6 +131,11 @@ impl<'e, 's, 'a, 'm, 'pm> NativeCallContext<'e, 's, 'a, 'm, 'pm> {
|
|||||||
pub fn engine(&self) -> &Engine {
|
pub fn engine(&self) -> &Engine {
|
||||||
self.engine
|
self.engine
|
||||||
}
|
}
|
||||||
|
/// Name of the function called.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn fn_name(&self) -> &str {
|
||||||
|
self.fn_name
|
||||||
|
}
|
||||||
/// The current source.
|
/// The current source.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn source(&self) -> Option<&str> {
|
pub fn source(&self) -> Option<&str> {
|
||||||
|
@ -327,10 +327,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut State, preserve_result: bool) {
|
|||||||
|
|
||||||
*stmt = if preserve_result {
|
*stmt = if preserve_result {
|
||||||
// -> { expr, Noop }
|
// -> { expr, Noop }
|
||||||
let mut statements = Vec::new();
|
Stmt::Block(vec![Stmt::Expr(expr), mem::take(&mut x.0)], pos)
|
||||||
statements.push(Stmt::Expr(expr));
|
|
||||||
statements.push(mem::take(&mut x.0));
|
|
||||||
Stmt::Block(statements, pos)
|
|
||||||
} else {
|
} else {
|
||||||
// -> expr
|
// -> expr
|
||||||
Stmt::Expr(expr)
|
Stmt::Expr(expr)
|
||||||
@ -415,8 +412,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut State, preserve_result: bool) {
|
|||||||
Stmt::Break(pos) => {
|
Stmt::Break(pos) => {
|
||||||
// Only a single break statement - turn into running the guard expression once
|
// Only a single break statement - turn into running the guard expression once
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
let mut statements = Vec::new();
|
let mut statements = vec![Stmt::Expr(mem::take(condition))];
|
||||||
statements.push(Stmt::Expr(mem::take(condition)));
|
|
||||||
if preserve_result {
|
if preserve_result {
|
||||||
statements.push(Stmt::Noop(pos))
|
statements.push(Stmt::Noop(pos))
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//! Implementations of [`serde::Serialize`].
|
//! Implementations of [`serde::Serialize`].
|
||||||
|
|
||||||
use crate::dynamic::Union;
|
use crate::dynamic::{Union, Variant};
|
||||||
use crate::stdlib::string::ToString;
|
use crate::stdlib::string::ToString;
|
||||||
use crate::{Dynamic, ImmutableString};
|
use crate::{Dynamic, ImmutableString};
|
||||||
use serde::ser::{Serialize, SerializeMap, Serializer};
|
use serde::ser::{Serialize, SerializeMap, Serializer};
|
||||||
@ -34,7 +34,7 @@ impl Serialize for Dynamic {
|
|||||||
}
|
}
|
||||||
Union::FnPtr(f, _) => ser.serialize_str(f.fn_name()),
|
Union::FnPtr(f, _) => ser.serialize_str(f.fn_name()),
|
||||||
#[cfg(not(feature = "no_std"))]
|
#[cfg(not(feature = "no_std"))]
|
||||||
Union::TimeStamp(_, _) => unimplemented!("serialization of timestamp is not supported"),
|
Union::TimeStamp(x, _) => ser.serialize_str(x.as_ref().type_name()),
|
||||||
|
|
||||||
Union::Variant(v, _) => ser.serialize_str((***v).type_name()),
|
Union::Variant(v, _) => ser.serialize_str((***v).type_name()),
|
||||||
|
|
||||||
|
@ -286,7 +286,8 @@ fn test_closures_external() -> Result<(), Box<EvalAltResult>> {
|
|||||||
let lib = [ast.as_ref()];
|
let lib = [ast.as_ref()];
|
||||||
|
|
||||||
// Create native call context
|
// Create native call context
|
||||||
let context = NativeCallContext::new(&engine, &lib);
|
let fn_name = fn_ptr.fn_name().to_string();
|
||||||
|
let context = NativeCallContext::new(&engine, &fn_name, &lib);
|
||||||
|
|
||||||
// Closure 'f' captures: the engine, the AST, and the curried function pointer
|
// Closure 'f' captures: the engine, the AST, and the curried function pointer
|
||||||
let f = move |x: INT| fn_ptr.call_dynamic(context, None, [x.into()]);
|
let f = move |x: INT| fn_ptr.call_dynamic(context, None, [x.into()]);
|
||||||
|
@ -101,3 +101,32 @@ fn test_plugins_package() -> Result<(), Box<EvalAltResult>> {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_plugins_parameters() -> Result<(), Box<EvalAltResult>> {
|
||||||
|
#[export_module]
|
||||||
|
mod rhai_std {
|
||||||
|
use rhai::*;
|
||||||
|
|
||||||
|
pub fn noop(_: &str) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut engine = Engine::new();
|
||||||
|
|
||||||
|
let std = exported_module!(rhai_std);
|
||||||
|
|
||||||
|
engine.register_static_module("std", std.into());
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
engine.eval::<String>(
|
||||||
|
r#"
|
||||||
|
let s = "hello";
|
||||||
|
std::noop(s);
|
||||||
|
s
|
||||||
|
"#
|
||||||
|
)?,
|
||||||
|
"hello"
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user