diff --git a/RELEASES.md b/RELEASES.md index cb37b9d8..db52a753 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -11,6 +11,7 @@ Breaking changes * `EvalAltResult::ErrorReadingScriptFile` is removed in favor of the new `EvalAltResult::ErrorSystem`. * `EvalAltResult::ErrorLoopBreak` is renamed to `EvalAltResult::LoopBreak`. * `Engine::register_raw_fn` and `FnPtr::call_dynamic` function signatures have changed. +* Callback signatures to `Engine::on_var` and `Engine::register_custom_syntax` have changed. New features ------------ diff --git a/doc/src/engine/custom-syntax.md b/doc/src/engine/custom-syntax.md index a0d38b9a..6bbe1157 100644 --- a/doc/src/engine/custom-syntax.md +++ b/doc/src/engine/custom-syntax.md @@ -114,25 +114,19 @@ Any custom syntax must include an _implementation_ of it. The function signature of an implementation is: -> `Fn(scope: &mut Scope, context: &mut EvalContext, inputs: &[Expression])` -> `-> Result>` +> `Fn(context: &mut EvalContext, inputs: &[Expression]) -> Result>` where: -* `scope: &mut Scope` - mutable reference to the current [`Scope`]; variables can be added to it. - -* `context: &mut EvalContext` - mutable reference to the current evaluation _context_ (**do not touch**) which exposes the following fields: +* `context: &mut EvalContext` - mutable reference to the current evaluation _context_, exposing the following: + * `context.scope: &mut Scope` - mutable reference to the current [`Scope`]; variables can be added to/removed from it. * `context.engine(): &Engine` - reference to the current [`Engine`]. * `context.namespace(): &Module` - reference to the current _global namespace_ (as a [module]) containing all script-defined functions. + * `context.this_ptr(): Option<&Dynamic>` - reference to the current bound [`this`] pointer, if any. * `context.call_level(): usize` - the current nesting level of function calls. * `inputs: &[Expression]` - a list of input expression trees. -#### WARNING - Lark's Vomit - -The `context` parameter contains the evaluation _context_ and should not be touched or Bad Things Happen™. -It should simply be passed straight-through the the [`Engine`]. - ### Access Arguments The most important argument is `inputs` where the matched identifiers (`$ident$`), expressions/statements (`$expr$`) @@ -152,8 +146,8 @@ Use the `EvalContext::eval_expression_tree` method to evaluate an arbitrary expr within the current evaluation context. ```rust -let expr = inputs.get(0).unwrap(); -let result = context.eval_expression_tree(scope, expr)?; +let expression = inputs.get(0).unwrap(); +let result = context.eval_expression_tree(expression)?; ``` ### Declare Variables @@ -163,15 +157,16 @@ New variables maybe declared (usually with a variable name that is passed in via It can simply be pushed into the [`Scope`]. However, beware that all new variables must be declared _prior_ to evaluating any expression tree. -In other words, any `Scope::push` calls must come _before_ any `EvalContext::eval_expression_tree` calls. +In other words, any [`Scope`] calls that change the list of must come _before_ any +`EvalContext::eval_expression_tree` calls. ```rust -let var_name = inputs[0].get_variable_name().unwrap().to_string(); -let expr = inputs.get(1).unwrap(); +let var_name = inputs[0].get_variable_name().unwrap(); +let expression = inputs.get(1).unwrap(); -scope.push(var_name, 0 as INT); // do this BEFORE 'context.eval_expression_tree'! +context.scope.push(var_name, 0 as INT); // do this BEFORE 'context.eval_expression_tree'! -let result = context.eval_expression_tree(context, scope, expr)?; +let result = context.eval_expression_tree(expression)?; ``` @@ -188,7 +183,6 @@ The syntax is passed simply as a slice of `&str`. ```rust // Custom syntax implementation fn implementation_func( - scope: &mut Scope, context: &mut EvalContext, inputs: &[Expression] ) -> Result> { @@ -196,15 +190,15 @@ fn implementation_func( let stmt = inputs.get(1).unwrap(); let condition = inputs.get(2).unwrap(); - // Push one new variable into the 'scope' BEFORE 'context.eval_expression_tree' - scope.push(var_name, 0 as INT); + // Push one new variable into the scope BEFORE 'context.eval_expression_tree' + context.scope.push(var_name, 0 as INT); loop { // Evaluate the statement block - context.eval_expression_tree(scope, stmt)?; + context.eval_expression_tree(stmt)?; // Evaluate the condition expression - let stop = !context.eval_expression_tree(scope, condition)? + let stop = !context.eval_expression_tree(condition)? .as_bool().map_err(|err| Box::new( EvalAltResult::ErrorMismatchDataType( "bool".to_string(), diff --git a/doc/src/engine/var.md b/doc/src/engine/var.md index f1119117..00b6a4fd 100644 --- a/doc/src/engine/var.md +++ b/doc/src/engine/var.md @@ -62,7 +62,7 @@ Function Signature The function signature passed to `Engine::on_var` takes the following form: -> `Fn(name: &str, index: usize, scope: &Scope, context: &EvalContext)` +> `Fn(name: &str, index: usize, context: &EvalContext)` > `-> Result, Box> + 'static` where: @@ -74,11 +74,11 @@ where: If `index` is zero, then there is no pre-calculated offset position and a search through the current [`Scope`] must be performed. -* `scope: &Scope` - reference to the current [`Scope`] containing all variables up to the current evaluation position. - * `context: &EvalContext` - reference to the current evaluation _context_, which exposes the following fields: + * `context.scope: &Scope` - reference to the current [`Scope`] containing all variables up to the current evaluation position. * `context.engine(): &Engine` - reference to the current [`Engine`]. * `context.namespace(): &Module` - reference to the current _global namespace_ (as a [module]) containing all script-defined functions. + * `context.this_ptr(): Option<&Dynamic>` - reference to the current bound [`this`] pointer, if any. * `context.call_level(): usize` - the current nesting level of function calls. ### Return Value diff --git a/src/api.rs b/src/api.rs index 07f0cef1..2e962b4f 100644 --- a/src/api.rs +++ b/src/api.rs @@ -3,12 +3,12 @@ use crate::any::{Dynamic, Variant}; use crate::engine::{Engine, EvalContext, Imports, State}; use crate::error::ParseError; -use crate::fn_native::{NativeCallContext, SendSync}; +use crate::fn_native::{FnCallArgs, NativeCallContext, SendSync}; use crate::optimize::OptimizationLevel; use crate::parser::AST; use crate::result::EvalAltResult; use crate::scope::Scope; -use crate::token::{lex, Position}; +use crate::token::Position; #[cfg(not(feature = "no_index"))] use crate::{ @@ -68,7 +68,7 @@ impl Engine { &mut self, name: &str, arg_types: &[TypeId], - func: impl Fn(NativeCallContext, &mut [&mut Dynamic]) -> Result> + func: impl Fn(NativeCallContext, &mut FnCallArgs) -> Result> + SendSync + 'static, ) -> &mut Self { @@ -913,7 +913,7 @@ impl Engine { scripts: &[&str], optimization_level: OptimizationLevel, ) -> Result { - let stream = lex(scripts, None, self); + let stream = self.lex(scripts, None); self.parse(&mut stream.peekable(), scope, optimization_level) } @@ -1067,7 +1067,7 @@ impl Engine { .into()); }; - let stream = lex( + let stream = self.lex( &scripts, if has_null { Some(Box::new(|token| match token { @@ -1078,7 +1078,6 @@ impl Engine { } else { None }, - self, ); let ast = self.parse_global_expr(&mut stream.peekable(), &scope, OptimizationLevel::None)?; @@ -1162,7 +1161,7 @@ impl Engine { script: &str, ) -> Result { let scripts = [script]; - let stream = lex(&scripts, None, self); + let stream = self.lex(&scripts, None); { let mut peekable = stream.peekable(); self.parse_global_expr(&mut peekable, scope, self.optimization_level) @@ -1323,7 +1322,7 @@ impl Engine { script: &str, ) -> Result> { let scripts = [script]; - let stream = lex(&scripts, None, self); + let stream = self.lex(&scripts, None); // No need to optimize a lone expression let ast = self.parse_global_expr(&mut stream.peekable(), scope, OptimizationLevel::None)?; @@ -1421,6 +1420,7 @@ impl Engine { }) .or_else(|err| match *err { EvalAltResult::Return(out, _) => Ok(out), + EvalAltResult::LoopBreak(_, _) => unreachable!(), _ => Err(err), }) .map(|v| (v, state.operations)) @@ -1464,7 +1464,7 @@ impl Engine { script: &str, ) -> Result<(), Box> { let scripts = [script]; - let stream = lex(&scripts, None, self); + let stream = self.lex(&scripts, None); let ast = self.parse(&mut stream.peekable(), scope, self.optimization_level)?; self.consume_ast_with_scope(scope, &ast) } @@ -1495,7 +1495,8 @@ impl Engine { .map_or_else( |err| match *err { EvalAltResult::Return(_, _) => Ok(()), - err => Err(Box::new(err)), + EvalAltResult::LoopBreak(_, _) => unreachable!(), + _ => Err(err), }, |_| Ok(()), ) @@ -1643,7 +1644,7 @@ impl Engine { lib: &Module, name: &str, this_ptr: &mut Option<&mut Dynamic>, - args: &mut [&mut Dynamic], + args: &mut FnCallArgs, ) -> Result> { let fn_def = lib .get_script_fn(name, args.len(), true) @@ -1713,7 +1714,7 @@ impl Engine { /// let mut engine = Engine::new(); /// /// // Register a variable resolver. - /// engine.on_var(|name, _, _, _| { + /// engine.on_var(|name, _, _| { /// match name { /// "MYSTIC_NUMBER" => Ok(Some(42_i64.into())), /// _ => Ok(None) @@ -1728,7 +1729,7 @@ impl Engine { #[inline(always)] pub fn on_var( &mut self, - callback: impl Fn(&str, usize, &Scope, &EvalContext) -> Result, Box> + callback: impl Fn(&str, usize, &EvalContext) -> Result, Box> + SendSync + 'static, ) -> &mut Self { diff --git a/src/engine.rs b/src/engine.rs index f5ce3981..5f1022c5 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -441,16 +441,17 @@ pub struct Limits { /// Context of a script evaluation process. #[derive(Debug)] -pub struct EvalContext<'e, 'a, 's, 'm, 't, 'd: 't> { +pub struct EvalContext<'e, 'x, 'px: 'x, 'a, 's, 'm, 't, 'pt: 't> { engine: &'e Engine, + pub scope: &'x mut Scope<'px>, pub(crate) mods: &'a mut Imports, pub(crate) state: &'s mut State, lib: &'m Module, - pub(crate) this_ptr: &'t mut Option<&'d mut Dynamic>, + pub(crate) this_ptr: &'t mut Option<&'pt mut Dynamic>, level: usize, } -impl<'e, 'a, 's, 'm, 't, 'd> EvalContext<'e, 'a, 's, 'm, 't, 'd> { +impl<'e, 'x, 'px, 'a, 's, 'm, 't, 'pt> EvalContext<'e, 'x, 'px, 'a, 's, 'm, 't, 'pt> { /// The current `Engine`. #[inline(always)] pub fn engine(&self) -> &'e Engine { @@ -469,6 +470,11 @@ impl<'e, 'a, 's, 'm, 't, 'd> EvalContext<'e, 'a, 's, 'm, 't, 'd> { pub fn namespace(&self) -> &'m Module { self.lib } + /// The current bound `this` pointer, if any. + #[inline(always)] + pub fn this_ptr(&self) -> Option<&Dynamic> { + self.this_ptr.as_ref().map(|v| &**v) + } /// The current nesting level of function calls. #[inline(always)] pub fn call_level(&self) -> usize { @@ -815,6 +821,7 @@ impl Engine { if let Some(ref resolve_var) = self.resolve_var { let context = EvalContext { engine: self, + scope, mods, state, lib, @@ -822,7 +829,7 @@ impl Engine { level: 0, }; if let Some(result) = - resolve_var(name, index, scope, &context).map_err(|err| err.fill_position(*pos))? + resolve_var(name, index, &context).map_err(|err| err.fill_position(*pos))? { return Ok((result.into(), name, ScopeEntryType::Constant, *pos)); } @@ -1742,17 +1749,22 @@ impl Engine { Expr::Unit(_) => Ok(().into()), Expr::Custom(x) => { - let func = (x.0).1.as_ref(); - let ep = (x.0).0.iter().map(|e| e.into()).collect::>(); + let func = (x.0).func(); + let expressions = (x.0) + .keywords() + .iter() + .map(Into::into) + .collect::>(); let mut context = EvalContext { engine: self, + scope, mods, state, lib, this_ptr, level, }; - func(scope, &mut context, ep.as_ref()) + func(&mut context, &expressions) } _ => unreachable!(), diff --git a/src/fn_call.rs b/src/fn_call.rs index 8260c0e1..8e9c1940 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -435,9 +435,11 @@ impl Engine { &self, lib: &Module, name: &str, - arg_types: &[TypeId], + arg_types: impl AsRef<[TypeId]>, pub_only: bool, ) -> bool { + let arg_types = arg_types.as_ref(); + let arg_len = if arg_types.is_empty() { usize::MAX } else { @@ -840,7 +842,7 @@ impl Engine { lib: &Module, this_ptr: &mut Option<&mut Dynamic>, name: &str, - args_expr: &[Expr], + args_expr: impl AsRef<[Expr]>, def_val: &Option, mut hash_script: u64, native: bool, @@ -848,6 +850,8 @@ impl Engine { capture: bool, level: usize, ) -> Result> { + let args_expr = args_expr.as_ref(); + // Handle Fn() if name == KEYWORD_FN_PTR && args_expr.len() == 1 { let hash_fn = calc_fn_hash(empty(), name, 1, once(TypeId::of::())); @@ -1085,11 +1089,13 @@ impl Engine { this_ptr: &mut Option<&mut Dynamic>, modules: &Option>, name: &str, - args_expr: &[Expr], + args_expr: impl AsRef<[Expr]>, def_val: Option, hash_script: u64, level: usize, ) -> Result> { + let args_expr = args_expr.as_ref(); + let modules = modules.as_ref().unwrap(); let mut arg_values: StaticVec<_>; let mut first_arg_value = None; diff --git a/src/fn_native.rs b/src/fn_native.rs index 8a3c9a1d..c37c8b28 100644 --- a/src/fn_native.rs +++ b/src/fn_native.rs @@ -6,7 +6,6 @@ use crate::module::Module; use crate::parser::{FnAccess, ScriptFnDef}; use crate::plugin::PluginFunction; use crate::result::EvalAltResult; -use crate::scope::Scope; use crate::token::{is_valid_identifier, Position}; use crate::utils::ImmutableString; use crate::{calc_fn_hash, StaticVec}; @@ -265,14 +264,12 @@ pub type Callback = Box R + Send + Sync + 'static>; /// A standard callback function. #[cfg(not(feature = "sync"))] -pub type OnVarCallback = Box< - dyn Fn(&str, usize, &Scope, &EvalContext) -> Result, Box> - + 'static, ->; +pub type OnVarCallback = + Box Result, Box> + 'static>; /// A standard callback function. #[cfg(feature = "sync")] pub type OnVarCallback = Box< - dyn Fn(&str, usize, &Scope, &EvalContext) -> Result, Box> + dyn Fn(&str, usize, &EvalContext) -> Result, Box> + Send + Sync + 'static, diff --git a/src/module/mod.rs b/src/module/mod.rs index 53fd915f..4c2b3780 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -536,11 +536,11 @@ impl Module { &mut self, name: impl Into, arg_types: &[TypeId], - func: impl Fn(NativeCallContext, &mut [&mut Dynamic]) -> Result> + func: impl Fn(NativeCallContext, &mut FnCallArgs) -> Result> + SendSync + 'static, ) -> u64 { - let f = move |context: NativeCallContext, args: &mut [&mut Dynamic]| { + let f = move |context: NativeCallContext, args: &mut FnCallArgs| { func(context, args).map(Dynamic::from) }; self.set_fn( diff --git a/src/parser.rs b/src/parser.rs index 8cedfae7..8f503caf 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -919,6 +919,19 @@ impl Hash for CustomExpr { } } +impl CustomExpr { + /// Get the keywords for this `CustomExpr`. + #[inline(always)] + pub fn keywords(&self) -> &[Expr] { + &self.0 + } + /// Get the implementation function for this `CustomExpr`. + #[inline(always)] + pub fn func(&self) -> &FnCustomSyntaxEval { + self.1.as_ref() + } +} + /// _[INTERNALS]_ A type wrapping a floating-point number. /// Exported under the `internals` feature only. /// @@ -2670,7 +2683,10 @@ fn parse_expr( // Adjust the variables stack match syntax.scope_delta { delta if delta > 0 => { - state.stack.push(("".to_string(), ScopeEntryType::Normal)) + state.stack.resize( + state.stack.len() + delta as usize, + ("".to_string(), ScopeEntryType::Normal), + ); } delta if delta < 0 && state.stack.len() <= delta.abs() as usize => { state.stack.clear() diff --git a/src/plugin.rs b/src/plugin.rs index 30edcc25..b2fde8e6 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -2,7 +2,7 @@ pub use crate::any::Dynamic; pub use crate::engine::Engine; -pub use crate::fn_native::{CallableFunction, NativeCallContext}; +pub use crate::fn_native::{CallableFunction, FnCallArgs, NativeCallContext}; pub use crate::fn_register::{RegisterFn, RegisterResultFn}; pub use crate::module::Module; pub use crate::parser::FnAccess; @@ -25,7 +25,7 @@ pub trait PluginFunction { fn call( &self, context: NativeCallContext, - args: &mut [&mut Dynamic], + args: &mut FnCallArgs, ) -> Result>; /// Is this plugin function a method? diff --git a/src/syntax.rs b/src/syntax.rs index 08b102b7..4e305f41 100644 --- a/src/syntax.rs +++ b/src/syntax.rs @@ -6,7 +6,6 @@ use crate::error::{LexError, ParseError}; use crate::fn_native::{SendSync, Shared}; use crate::parser::Expr; use crate::result::EvalAltResult; -use crate::scope::Scope; use crate::token::{is_valid_identifier, Position, Token}; use crate::StaticVec; @@ -19,12 +18,11 @@ use crate::stdlib::{ /// A general expression evaluation trait object. #[cfg(not(feature = "sync"))] pub type FnCustomSyntaxEval = - dyn Fn(&mut Scope, &mut EvalContext, &[Expression]) -> Result>; + dyn Fn(&mut EvalContext, &[Expression]) -> Result>; /// A general expression evaluation trait object. #[cfg(feature = "sync")] -pub type FnCustomSyntaxEval = dyn Fn(&mut Scope, &mut EvalContext, &[Expression]) -> Result> - + Send - + Sync; +pub type FnCustomSyntaxEval = + dyn Fn(&mut EvalContext, &[Expression]) -> Result> + Send + Sync; /// An expression sub-tree in an AST. #[derive(Debug, Clone, Hash)] @@ -55,7 +53,7 @@ impl Expression<'_> { } } -impl EvalContext<'_, '_, '_, '_, '_, '_> { +impl EvalContext<'_, '_, '_, '_, '_, '_, '_, '_> { /// Evaluate an expression tree. /// /// ## WARNING - Low Level API @@ -64,11 +62,10 @@ impl EvalContext<'_, '_, '_, '_, '_, '_> { #[inline(always)] pub fn eval_expression_tree( &mut self, - scope: &mut Scope, expr: &Expression, ) -> Result> { self.engine().eval_expr( - scope, + self.scope, self.mods, self.state, self.namespace(), @@ -101,12 +98,14 @@ impl Engine { /// * `func` is the implementation function. pub fn register_custom_syntax + ToString>( &mut self, - keywords: &[S], + keywords: impl AsRef<[S]>, new_vars: isize, - func: impl Fn(&mut Scope, &mut EvalContext, &[Expression]) -> Result> + func: impl Fn(&mut EvalContext, &[Expression]) -> Result> + SendSync + 'static, ) -> Result<&mut Self, ParseError> { + let keywords = keywords.as_ref(); + let mut segments: StaticVec<_> = Default::default(); for s in keywords { diff --git a/src/token.rs b/src/token.rs index 418765d6..55dc2d38 100644 --- a/src/token.rs +++ b/src/token.rs @@ -1736,31 +1736,33 @@ impl<'a> Iterator for TokenIterator<'a, '_> { } } -/// Tokenize an input text stream. -#[inline] -pub fn lex<'a, 'e>( - input: &'a [&'a str], - map: Option Token>>, - engine: &'e Engine, -) -> TokenIterator<'a, 'e> { - TokenIterator { - engine, - state: TokenizeState { - #[cfg(not(feature = "unchecked"))] - max_string_size: engine.limits_set.max_string_size, - #[cfg(feature = "unchecked")] - max_string_size: 0, - non_unary: false, - comment_level: 0, - end_with_none: false, - include_comments: false, - }, - pos: Position::new(1, 0), - stream: MultiInputsStream { - buf: None, - streams: input.iter().map(|s| s.chars().peekable()).collect(), - index: 0, - }, - map, +impl Engine { + /// Tokenize an input text stream. + #[inline] + pub fn lex<'a, 'e>( + &'e self, + input: impl IntoIterator, + map: Option Token>>, + ) -> TokenIterator<'a, 'e> { + TokenIterator { + engine: self, + state: TokenizeState { + #[cfg(not(feature = "unchecked"))] + max_string_size: self.limits_set.max_string_size, + #[cfg(feature = "unchecked")] + max_string_size: 0, + non_unary: false, + comment_level: 0, + end_with_none: false, + include_comments: false, + }, + pos: Position::new(1, 0), + stream: MultiInputsStream { + buf: None, + streams: input.into_iter().map(|s| s.chars().peekable()).collect(), + index: 0, + }, + map, + } } } diff --git a/tests/call_fn.rs b/tests/call_fn.rs index 4d4e3552..7e9170b0 100644 --- a/tests/call_fn.rs +++ b/tests/call_fn.rs @@ -1,7 +1,5 @@ #![cfg(not(feature = "no_function"))] -use rhai::{ - Dynamic, Engine, EvalAltResult, FnPtr, Func, Module, ParseErrorType, RegisterFn, Scope, INT, -}; +use rhai::{Engine, EvalAltResult, FnPtr, Func, ParseErrorType, RegisterFn, Scope, INT}; use std::any::TypeId; #[test] diff --git a/tests/syntax.rs b/tests/syntax.rs index f9c5acda..c0433e9e 100644 --- a/tests/syntax.rs +++ b/tests/syntax.rs @@ -1,4 +1,4 @@ -use rhai::{Engine, EvalAltResult, EvalContext, Expression, ParseErrorType, Scope, INT}; +use rhai::{Engine, EvalAltResult, EvalContext, Expression, ParseErrorType, INT}; #[test] fn test_custom_syntax() -> Result<(), Box> { @@ -22,18 +22,18 @@ fn test_custom_syntax() -> Result<(), Box> { "do", "|", "$ident$", "|", "->", "$block$", "while", "$expr$", ], 1, - |scope: &mut Scope, context: &mut EvalContext, inputs: &[Expression]| { + |context: &mut EvalContext, inputs: &[Expression]| { let var_name = inputs[0].get_variable_name().unwrap().to_string(); let stmt = inputs.get(1).unwrap(); let condition = inputs.get(2).unwrap(); - scope.push(var_name, 0 as INT); + context.scope.push(var_name, 0 as INT); loop { - context.eval_expression_tree(scope, stmt)?; + context.eval_expression_tree(stmt)?; let stop = !context - .eval_expression_tree(scope, condition)? + .eval_expression_tree(condition)? .as_bool() .map_err(|err| { Box::new(EvalAltResult::ErrorMismatchDataType( @@ -68,7 +68,7 @@ fn test_custom_syntax() -> Result<(), Box> { // The first symbol must be an identifier assert_eq!( *engine - .register_custom_syntax(&["!"], 0, |_, _, _| Ok(().into())) + .register_custom_syntax(&["!"], 0, |_, _| Ok(().into())) .expect_err("should error") .0, ParseErrorType::BadInput("Improper symbol for custom syntax: '!'".to_string()) diff --git a/tests/var_scope.rs b/tests/var_scope.rs index ede4ef1d..4faf37b5 100644 --- a/tests/var_scope.rs +++ b/tests/var_scope.rs @@ -62,7 +62,7 @@ fn test_var_resolver() -> Result<(), Box> { scope.push("chameleon", 123 as INT); scope.push("DO_NOT_USE", 999 as INT); - engine.on_var(|name, _, scope, _| { + engine.on_var(|name, _, context| { match name { "MYSTIC_NUMBER" => Ok(Some((42 as INT).into())), // Override a variable - make it not found even if it exists! @@ -70,9 +70,13 @@ fn test_var_resolver() -> Result<(), Box> { Err(EvalAltResult::ErrorVariableNotFound(name.to_string(), Position::none()).into()) } // Silently maps 'chameleon' into 'innocent'. - "chameleon" => scope.get_value("innocent").map(Some).ok_or_else(|| { - EvalAltResult::ErrorVariableNotFound(name.to_string(), Position::none()).into() - }), + "chameleon" => context + .scope + .get_value("innocent") + .map(Some) + .ok_or_else(|| { + EvalAltResult::ErrorVariableNotFound(name.to_string(), Position::none()).into() + }), // Return Ok(None) to continue with the normal variable resolution process. _ => Ok(None), }