From ea86888638c930963332723869a7782da4c7c9d4 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Mon, 6 Jul 2020 12:04:02 +0800 Subject: [PATCH] Add new &Module parameter to native functions. --- doc/src/engine/call-fn.md | 28 +++++++------ src/api.rs | 78 +++++++++++++++++-------------------- src/engine.rs | 9 ++--- src/fn_native.rs | 5 ++- src/fn_register.rs | 3 +- src/module.rs | 28 ++++++------- src/packages/array_basic.rs | 8 +++- src/packages/string_more.rs | 4 +- src/parser.rs | 6 +++ tests/call_fn.rs | 37 ++++++++---------- 10 files changed, 107 insertions(+), 99 deletions(-) diff --git a/doc/src/engine/call-fn.md b/doc/src/engine/call-fn.md index fd9255d0..7a49d6e4 100644 --- a/doc/src/engine/call-fn.md +++ b/doc/src/engine/call-fn.md @@ -56,19 +56,20 @@ let result: () = engine.call_fn(&mut scope, &ast, "hidden", ())?; ``` -`Engine::call_fn_dynamic` ------------------------- +Low-Level API - `Engine::call_fn_dynamic` +---------------------------------------- For more control, construct all arguments as `Dynamic` values and use `Engine::call_fn_dynamic`, passing it -anything that implements `IntoIterator` (such as a simple `Vec`): +anything that implements `AsMut` (such as a simple array or a `Vec`): ```rust -let result: Dynamic = engine.call_fn_dynamic( - &mut scope, // scope to use - &ast, // AST to use - "hello", // function entry-point - None, // 'this' pointer, if any - [ String::from("abc").into(), 123_i64.into() ])?; // arguments +let result = engine.call_fn_dynamic( + &mut scope, // scope to use + ast.into(), // get 'Module' from 'AST' + "hello", // function entry-point + None, // 'this' pointer, if any + [ String::from("abc").into(), 123_i64.into() ] // arguments + )?; ``` @@ -82,8 +83,13 @@ let ast = engine.compile("fn action(x) { this += x; }")?; let mut value: Dynamic = 1_i64.into(); -let result = engine.call_fn_dynamic(&mut scope, &ast, "action", Some(&mut value), [ 41_i64.into() ])?; -// ^^^^^^^^^^^^^^^^ binding the 'this' pointer +let result = engine.call_fn_dynamic( + &mut scope, + ast.into(), + "action", + Some(&mut value), // binding the 'this' pointer + [ 41_i64.into() ] + )?; assert_eq!(value.as_int().unwrap(), 42); ``` diff --git a/src/api.rs b/src/api.rs index 74b78b84..343caaed 100644 --- a/src/api.rs +++ b/src/api.rs @@ -6,6 +6,7 @@ use crate::error::ParseError; use crate::fn_call::FuncArgs; use crate::fn_native::{IteratorFn, SendSync}; use crate::fn_register::RegisterFn; +use crate::module::Module; use crate::optimize::{optimize_into_ast, OptimizationLevel}; use crate::parser::AST; use crate::result::EvalAltResult; @@ -53,10 +54,10 @@ impl Engine { name: &str, args: &[TypeId], - #[cfg(not(feature = "sync"))] func: impl Fn(&Engine, &mut [&mut Dynamic]) -> Result> + #[cfg(not(feature = "sync"))] func: impl Fn(&Engine, &Module, &mut [&mut Dynamic]) -> Result> + 'static, - #[cfg(feature = "sync")] func: impl Fn(&Engine, &mut [&mut Dynamic]) -> Result> + #[cfg(feature = "sync")] func: impl Fn(&Engine, &Module, &mut [&mut Dynamic]) -> Result> + Send + Sync + 'static, @@ -459,7 +460,7 @@ impl Engine { self.register_indexer_set(setter); } - /// Compile a string into an [`AST`], which can be used later for evaluation. + /// Compile a string into an `AST`, which can be used later for evaluation. /// /// # Example /// @@ -482,7 +483,7 @@ impl Engine { self.compile_with_scope(&Scope::new(), script) } - /// Compile a string into an [`AST`] using own scope, which can be used later for evaluation. + /// Compile a string into an `AST` using own scope, which can be used later for evaluation. /// /// The scope is useful for passing constants into the script for optimization /// when using `OptimizationLevel::Full`. @@ -525,7 +526,7 @@ impl Engine { } /// When passed a list of strings, first join the strings into one large script, - /// and then compile them into an [`AST`] using own scope, which can be used later for evaluation. + /// and then compile them into an `AST` using own scope, which can be used later for evaluation. /// /// The scope is useful for passing constants into the script for optimization /// when using `OptimizationLevel::Full`. @@ -578,7 +579,7 @@ impl Engine { self.compile_with_scope_and_optimization_level(scope, scripts, self.optimization_level) } - /// Join a list of strings and compile into an [`AST`] using own scope at a specific optimization level. + /// Join a list of strings and compile into an `AST` using own scope at a specific optimization level. pub(crate) fn compile_with_scope_and_optimization_level( &self, scope: &Scope, @@ -614,7 +615,7 @@ impl Engine { Ok(contents) } - /// Compile a script file into an [`AST`], which can be used later for evaluation. + /// Compile a script file into an `AST`, which can be used later for evaluation. /// /// # Example /// @@ -640,7 +641,7 @@ impl Engine { self.compile_file_with_scope(&Scope::new(), path) } - /// Compile a script file into an [`AST`] using own scope, which can be used later for evaluation. + /// Compile a script file into an `AST` using own scope, which can be used later for evaluation. /// /// The scope is useful for passing constants into the script for optimization /// when using `OptimizationLevel::Full`. @@ -722,7 +723,7 @@ impl Engine { self.eval_ast_with_scope(&mut scope, &ast) } - /// Compile a string containing an expression into an [`AST`], + /// Compile a string containing an expression into an `AST`, /// which can be used later for evaluation. /// /// # Example @@ -746,7 +747,7 @@ impl Engine { self.compile_expression_with_scope(&Scope::new(), script) } - /// Compile a string containing an expression into an [`AST`] using own scope, + /// Compile a string containing an expression into an `AST` using own scope, /// which can be used later for evaluation. /// /// The scope is useful for passing constants into the script for optimization @@ -954,7 +955,7 @@ impl Engine { self.eval_ast_with_scope(scope, &ast) } - /// Evaluate an [`AST`]. + /// Evaluate an `AST`. /// /// # Example /// @@ -976,7 +977,7 @@ impl Engine { self.eval_ast_with_scope(&mut Scope::new(), ast) } - /// Evaluate an [`AST`] with own scope. + /// Evaluate an `AST` with own scope. /// /// # Example /// @@ -1024,7 +1025,7 @@ impl Engine { }); } - /// Evaluate an [`AST`] with own scope. + /// Evaluate an `AST` with own scope. pub(crate) fn eval_ast_with_scope_raw<'a>( &self, scope: &mut Scope, @@ -1090,7 +1091,7 @@ impl Engine { self.consume_ast_with_scope(&mut Scope::new(), ast) } - /// Evaluate an [`AST`] with own scope, but throw away the result and only return error (if any). + /// Evaluate an `AST` with own scope, but throw away the result and only return error (if any). /// Useful for when you don't need the result, but still need to keep track of possible errors. pub fn consume_ast_with_scope( &self, @@ -1114,7 +1115,7 @@ impl Engine { ) } - /// Call a script function defined in an [`AST`] with multiple arguments. + /// Call a script function defined in an `AST` with multiple arguments. /// Arguments are passed as a tuple. /// /// # Example @@ -1159,7 +1160,8 @@ impl Engine { args: A, ) -> Result> { let mut arg_values = args.into_vec(); - let result = self.call_fn_dynamic_raw(scope, ast, name, &mut None, arg_values.as_mut())?; + let result = + self.call_fn_dynamic_raw(scope, ast.lib(), name, &mut None, arg_values.as_mut())?; let typ = self.map_type_name(result.type_name()); @@ -1172,7 +1174,7 @@ impl Engine { }); } - /// Call a script function defined in an [`AST`] with multiple `Dynamic` arguments + /// Call a script function defined in an `AST` with multiple `Dynamic` arguments /// and optionally a value for binding to the 'this' pointer. /// /// ## WARNING @@ -1203,19 +1205,19 @@ impl Engine { /// scope.push("foo", 42_i64); /// /// // Call the script-defined function - /// let result = engine.call_fn_dynamic(&mut scope, &ast, "add", None, [ String::from("abc").into(), 123_i64.into() ])?; - /// // ^^^^ no 'this' pointer + /// let result = engine.call_fn_dynamic(&mut scope, ast.into(), "add", None, [ String::from("abc").into(), 123_i64.into() ])?; + /// // ^^^^ no 'this' pointer /// assert_eq!(result.cast::(), 168); /// - /// let result = engine.call_fn_dynamic(&mut scope, &ast, "add1", None, [ String::from("abc").into() ])?; + /// let result = engine.call_fn_dynamic(&mut scope, ast.into(), "add1", None, [ String::from("abc").into() ])?; /// assert_eq!(result.cast::(), 46); /// - /// let result = engine.call_fn_dynamic(&mut scope, &ast, "bar", None, [])?; + /// let result = engine.call_fn_dynamic(&mut scope, ast.into(), "bar", None, [])?; /// assert_eq!(result.cast::(), 21); /// /// let mut value: Dynamic = 1_i64.into(); - /// let result = engine.call_fn_dynamic(&mut scope, &ast, "action", Some(&mut value), [ 41_i64.into() ])?; - /// // ^^^^^^^^^^^^^^^^ binding the 'this' pointer + /// let result = engine.call_fn_dynamic(&mut scope, ast.into(), "action", Some(&mut value), [ 41_i64.into() ])?; + /// // ^^^^^^^^^^^^^^^^ binding the 'this' pointer /// assert_eq!(value.as_int().unwrap(), 42); /// # } /// # Ok(()) @@ -1225,15 +1227,15 @@ impl Engine { pub fn call_fn_dynamic( &self, scope: &mut Scope, - ast: &AST, + lib: &Module, name: &str, mut this_ptr: Option<&mut Dynamic>, mut arg_values: impl AsMut<[Dynamic]>, ) -> Result> { - self.call_fn_dynamic_raw(scope, ast, name, &mut this_ptr, arg_values.as_mut()) + self.call_fn_dynamic_raw(scope, lib, name, &mut this_ptr, arg_values.as_mut()) } - /// Call a script function defined in an [`AST`] with multiple `Dynamic` arguments. + /// Call a script function defined in an `AST` with multiple `Dynamic` arguments. /// /// ## WARNING /// @@ -1245,14 +1247,14 @@ impl Engine { pub(crate) fn call_fn_dynamic_raw( &self, scope: &mut Scope, - ast: &AST, + lib: &Module, name: &str, this_ptr: &mut Option<&mut Dynamic>, arg_values: &mut [Dynamic], ) -> Result> { let mut args: StaticVec<_> = arg_values.iter_mut().collect(); - let fn_def = get_script_function_by_signature(ast.lib(), name, args.len(), true) - .ok_or_else(|| { + let fn_def = + get_script_function_by_signature(lib, name, args.len(), true).ok_or_else(|| { Box::new(EvalAltResult::ErrorFunctionNotFound( name.into(), Position::none(), @@ -1264,27 +1266,19 @@ impl Engine { let args = args.as_mut(); self.call_script_fn( - scope, - &mut mods, - &mut state, - ast.lib(), - this_ptr, - name, - fn_def, - args, - 0, + scope, &mut mods, &mut state, lib, this_ptr, name, fn_def, args, 0, ) } - /// Optimize the [`AST`] with constants defined in an external Scope. - /// An optimized copy of the [`AST`] is returned while the original [`AST`] is consumed. + /// Optimize the `AST` with constants defined in an external Scope. + /// An optimized copy of the `AST` is returned while the original `AST` is consumed. /// /// Although optimization is performed by default during compilation, sometimes it is necessary to /// _re_-optimize an AST. For example, when working with constants that are passed in via an - /// external scope, it will be more efficient to optimize the [`AST`] once again to take advantage + /// external scope, it will be more efficient to optimize the `AST` once again to take advantage /// of the new constants. /// - /// With this method, it is no longer necessary to recompile a large script. The script [`AST`] can be + /// With this method, it is no longer necessary to recompile a large script. The script `AST` can be /// compiled just once. Before evaluation, constants are passed into the `Engine` via an external scope /// (i.e. with `scope.push_constant(...)`). Then, the `AST is cloned and the copy re-optimized before running. #[cfg(not(feature = "no_optimize"))] diff --git a/src/engine.rs b/src/engine.rs index b3eb7d7a..93f850b7 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -661,7 +661,7 @@ impl Engine { } // Run external function - let result = func.get_native_fn()(self, args)?; + let result = func.get_native_fn()(self, lib, args)?; // Restore the original reference restore_first_arg(old_this_ptr, args); @@ -1616,7 +1616,7 @@ impl Engine { .or_else(|| self.packages.get_fn(hash_fn)) { // Overriding exact implementation - func(self, &mut [lhs_ptr, &mut rhs_val])?; + func(self, lib, &mut [lhs_ptr, &mut rhs_val])?; } else if run_builtin_op_assignment(op, lhs_ptr, &rhs_val)?.is_none() { // Not built in, map to `var = var op rhs` let op = &op[..op.len() - 1]; // extract operator without = @@ -1885,9 +1885,8 @@ impl Engine { ) .map_err(|err| err.new_position(*pos)) } - Ok(f) => { - f.get_native_fn()(self, args.as_mut()).map_err(|err| err.new_position(*pos)) - } + Ok(f) => f.get_native_fn()(self, lib, args.as_mut()) + .map_err(|err| err.new_position(*pos)), Err(err) => match *err { EvalAltResult::ErrorFunctionNotFound(_, _) if def_val.is_some() => { Ok(def_val.clone().unwrap()) diff --git a/src/fn_native.rs b/src/fn_native.rs index 1279e430..49cb4570 100644 --- a/src/fn_native.rs +++ b/src/fn_native.rs @@ -1,5 +1,6 @@ use crate::any::Dynamic; use crate::engine::Engine; +use crate::module::Module; use crate::parser::ScriptFnDef; use crate::result::EvalAltResult; use crate::utils::ImmutableString; @@ -79,11 +80,11 @@ impl> From for FnPtr { /// A general function trail object. #[cfg(not(feature = "sync"))] -pub type FnAny = dyn Fn(&Engine, &mut FnCallArgs) -> Result>; +pub type FnAny = dyn Fn(&Engine, &Module, &mut FnCallArgs) -> Result>; /// A general function trail object. #[cfg(feature = "sync")] pub type FnAny = - dyn Fn(&Engine, &mut FnCallArgs) -> Result> + Send + Sync; + dyn Fn(&Engine, &Module, &mut FnCallArgs) -> Result> + Send + Sync; /// A standard function that gets an iterator from a type. pub type IteratorFn = fn(Dynamic) -> Box>; diff --git a/src/fn_register.rs b/src/fn_register.rs index 1b07cbe8..01a3255f 100644 --- a/src/fn_register.rs +++ b/src/fn_register.rs @@ -4,6 +4,7 @@ use crate::any::{Dynamic, Variant}; use crate::engine::Engine; use crate::fn_native::{CallableFunction, FnAny, FnCallArgs, SendSync}; +use crate::module::Module; use crate::parser::FnAccess; use crate::result::EvalAltResult; use crate::utils::ImmutableString; @@ -119,7 +120,7 @@ macro_rules! make_func { // ^ function parameter generic type name (A, B, C etc.) // ^ dereferencing function - Box::new(move |_: &Engine, args: &mut FnCallArgs| { + Box::new(move |_: &Engine, _: &Module, args: &mut FnCallArgs| { // The arguments are assumed to be of the correct number and types! #[allow(unused_variables, unused_mut)] diff --git a/src/module.rs b/src/module.rs index 7ae8d355..065bffab 100644 --- a/src/module.rs +++ b/src/module.rs @@ -373,9 +373,11 @@ impl Module { &mut self, name: impl Into, args: &[TypeId], - func: impl Fn(&Engine, &mut [&mut Dynamic]) -> FuncReturn + SendSync + 'static, + func: impl Fn(&Engine, &Module, &mut [&mut Dynamic]) -> FuncReturn + SendSync + 'static, ) -> u64 { - let f = move |engine: &Engine, args: &mut FnCallArgs| func(engine, args).map(Dynamic::from); + let f = move |engine: &Engine, lib: &Module, args: &mut FnCallArgs| { + func(engine, lib, args).map(Dynamic::from) + }; self.set_fn( name, Public, @@ -402,7 +404,7 @@ impl Module { name: impl Into, func: impl Fn() -> FuncReturn + SendSync + 'static, ) -> u64 { - let f = move |_: &Engine, _: &mut FnCallArgs| func().map(Dynamic::from); + let f = move |_: &Engine, _: &Module, _: &mut FnCallArgs| func().map(Dynamic::from); let args = []; self.set_fn( name, @@ -430,7 +432,7 @@ impl Module { name: impl Into, func: impl Fn(A) -> FuncReturn + SendSync + 'static, ) -> u64 { - let f = move |_: &Engine, args: &mut FnCallArgs| { + let f = move |_: &Engine, _: &Module, args: &mut FnCallArgs| { func(mem::take(args[0]).cast::()).map(Dynamic::from) }; let args = [TypeId::of::()]; @@ -460,7 +462,7 @@ impl Module { name: impl Into, func: impl Fn(&mut A) -> FuncReturn + SendSync + 'static, ) -> u64 { - let f = move |_: &Engine, args: &mut FnCallArgs| { + let f = move |_: &Engine, _: &Module, args: &mut FnCallArgs| { func(args[0].downcast_mut::().unwrap()).map(Dynamic::from) }; let args = [TypeId::of::()]; @@ -514,7 +516,7 @@ impl Module { name: impl Into, func: impl Fn(A, B) -> FuncReturn + SendSync + 'static, ) -> u64 { - let f = move |_: &Engine, args: &mut FnCallArgs| { + let f = move |_: &Engine, _: &Module, args: &mut FnCallArgs| { let a = mem::take(args[0]).cast::(); let b = mem::take(args[1]).cast::(); @@ -550,7 +552,7 @@ impl Module { name: impl Into, func: impl Fn(&mut A, B) -> FuncReturn + SendSync + 'static, ) -> u64 { - let f = move |_: &Engine, args: &mut FnCallArgs| { + let f = move |_: &Engine, _: &Module, args: &mut FnCallArgs| { let b = mem::take(args[1]).cast::(); let a = args[0].downcast_mut::().unwrap(); @@ -641,7 +643,7 @@ impl Module { name: impl Into, func: impl Fn(A, B, C) -> FuncReturn + SendSync + 'static, ) -> u64 { - let f = move |_: &Engine, args: &mut FnCallArgs| { + let f = move |_: &Engine, _: &Module, args: &mut FnCallArgs| { let a = mem::take(args[0]).cast::(); let b = mem::take(args[1]).cast::(); let c = mem::take(args[2]).cast::(); @@ -683,7 +685,7 @@ impl Module { name: impl Into, func: impl Fn(&mut A, B, C) -> FuncReturn + SendSync + 'static, ) -> u64 { - let f = move |_: &Engine, args: &mut FnCallArgs| { + let f = move |_: &Engine, _: &Module, args: &mut FnCallArgs| { let b = mem::take(args[1]).cast::(); let c = mem::take(args[2]).cast::(); let a = args[0].downcast_mut::().unwrap(); @@ -720,7 +722,7 @@ impl Module { &mut self, func: impl Fn(&mut A, B, A) -> FuncReturn<()> + SendSync + 'static, ) -> u64 { - let f = move |_: &Engine, args: &mut FnCallArgs| { + let f = move |_: &Engine, _: &Module, args: &mut FnCallArgs| { let b = mem::take(args[1]).cast::(); let c = mem::take(args[2]).cast::(); let a = args[0].downcast_mut::().unwrap(); @@ -762,7 +764,7 @@ impl Module { name: impl Into, func: impl Fn(A, B, C, D) -> FuncReturn + SendSync + 'static, ) -> u64 { - let f = move |_: &Engine, args: &mut FnCallArgs| { + let f = move |_: &Engine, _: &Module, args: &mut FnCallArgs| { let a = mem::take(args[0]).cast::(); let b = mem::take(args[1]).cast::(); let c = mem::take(args[2]).cast::(); @@ -811,7 +813,7 @@ impl Module { name: impl Into, func: impl Fn(&mut A, B, C, D) -> FuncReturn + SendSync + 'static, ) -> u64 { - let f = move |_: &Engine, args: &mut FnCallArgs| { + let f = move |_: &Engine, _: &Module, args: &mut FnCallArgs| { let b = mem::take(args[1]).cast::(); let c = mem::take(args[2]).cast::(); let d = mem::take(args[3]).cast::(); @@ -942,7 +944,7 @@ impl Module { .map(|f| f.get_shared_fn_def()) } - /// Create a new `Module` by evaluating an [`AST`]. + /// Create a new `Module` by evaluating an `AST`. /// /// # Examples /// diff --git a/src/packages/array_basic.rs b/src/packages/array_basic.rs index 7c7b5681..acaa1132 100644 --- a/src/packages/array_basic.rs +++ b/src/packages/array_basic.rs @@ -3,7 +3,7 @@ use crate::any::{Dynamic, Variant}; use crate::def_package; use crate::engine::{Array, Engine}; -use crate::module::FuncReturn; +use crate::module::{FuncReturn, Module}; use crate::parser::{ImmutableString, INT}; use crate::result::EvalAltResult; use crate::token::Position; @@ -25,7 +25,11 @@ fn ins(list: &mut Array, position: INT, item: T) -> FuncRetu } Ok(()) } -fn pad(engine: &Engine, args: &mut [&mut Dynamic]) -> FuncReturn<()> { +fn pad( + engine: &Engine, + _: &Module, + args: &mut [&mut Dynamic], +) -> FuncReturn<()> { let len = *args[1].downcast_ref::().unwrap(); // Check if array will be over max size limit diff --git a/src/packages/string_more.rs b/src/packages/string_more.rs index e6acbbb9..5ae39db6 100644 --- a/src/packages/string_more.rs +++ b/src/packages/string_more.rs @@ -1,7 +1,7 @@ use crate::any::Dynamic; use crate::def_package; use crate::engine::Engine; -use crate::module::FuncReturn; +use crate::module::{FuncReturn, Module}; use crate::parser::{ImmutableString, INT}; use crate::result::EvalAltResult; use crate::token::Position; @@ -226,7 +226,7 @@ def_package!(crate:MoreStringPackage:"Additional string utilities, including str lib.set_fn_var_args( "pad", &[TypeId::of::(), TypeId::of::(), TypeId::of::()], - |engine: &Engine, args: &mut [&mut Dynamic]| { + |engine: &Engine, _: &Module, args: &mut [&mut Dynamic]| { let len = *args[1].downcast_ref::< INT>().unwrap(); // Check if string will be over max size limit diff --git a/src/parser.rs b/src/parser.rs index 7b919b8d..02cf1571 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -298,6 +298,12 @@ impl Add for &AST { } } +impl<'a> From<&'a AST> for &'a Module { + fn from(ast: &'a AST) -> Self { + ast.lib() + } +} + /// A type representing the access mode of a scripted function. #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] pub enum FnAccess { diff --git a/tests/call_fn.rs b/tests/call_fn.rs index f217073e..690577ce 100644 --- a/tests/call_fn.rs +++ b/tests/call_fn.rs @@ -1,6 +1,7 @@ #![cfg(not(feature = "no_function"))] use rhai::{ - Dynamic, Engine, EvalAltResult, Func, ImmutableString, ParseError, ParseErrorType, Scope, INT, + Dynamic, Engine, EvalAltResult, Func, ImmutableString, Module, ParseError, ParseErrorType, + Scope, INT, }; #[test] @@ -117,17 +118,6 @@ fn test_anonymous_fn() -> Result<(), Box> { fn test_fn_ptr() -> Result<(), Box> { let mut engine = Engine::new(); - let ast = engine.compile( - r#" - fn foo(x) { this += x; } - - let x = 41; - x.bar("foo", 1); - x - "#, - )?; - let ast_clone = ast.clone(); - engine.register_raw_fn( "bar", &[ @@ -135,24 +125,29 @@ fn test_fn_ptr() -> Result<(), Box> { std::any::TypeId::of::(), std::any::TypeId::of::(), ], - move |engine: &Engine, args: &mut [&mut Dynamic]| { + move |engine: &Engine, lib: &Module, args: &mut [&mut Dynamic]| { let callback = args[1].clone().cast::(); let value = args[2].clone(); let this_ptr = args.get_mut(0).unwrap(); - engine.call_fn_dynamic( - &mut Scope::new(), - &ast_clone, - &callback, - Some(this_ptr), - [value], - )?; + engine.call_fn_dynamic(&mut Scope::new(), lib, &callback, Some(this_ptr), [value])?; Ok(().into()) }, ); - assert_eq!(engine.eval_ast::(&ast)?, 42); + assert_eq!( + engine.eval::( + r#" + fn foo(x) { this += x; } + + let x = 41; + x.bar("foo", 1); + x + "# + )?, + 42 + ); Ok(()) }