From 20cff87e148642e23f288cf882e980b7919bbe36 Mon Sep 17 00:00:00 2001 From: Ilya Lakhin Date: Sun, 9 Aug 2020 18:35:29 +0700 Subject: [PATCH 1/3] False-positive capturing prevention bug fix --- src/parser.rs | 5 ++++- tests/closures.rs | 24 ++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/parser.rs b/src/parser.rs index cc0b91c8..a47f49e8 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -414,7 +414,8 @@ struct ParseState<'e> { /// Tracks a list of external variables (variables that are not explicitly declared in the scope). #[cfg(not(feature = "no_closure"))] externals: HashMap, - /// An indicator that disables variable capturing into externals one single time. + /// An indicator that disables variable capturing into externals one single time + /// up until the nearest consumed Identifier token. /// If set to false the next call to `access_var` will not capture the variable. /// All consequent calls to `access_var` will not be affected #[cfg(not(feature = "no_closure"))] @@ -1637,6 +1638,8 @@ fn parse_primary( // Function call Token::Identifier(s) if *next_token == Token::LeftParen || *next_token == Token::Bang => { + // Once the identifier consumed we must enable next variables capturing + state.allow_capture = true; Expr::Variable(Box::new(((s, settings.pos), None, 0, None))) } // Normal variable access diff --git a/tests/closures.rs b/tests/closures.rs index d7684540..66dad215 100644 --- a/tests/closures.rs +++ b/tests/closures.rs @@ -1,6 +1,7 @@ #![cfg(not(feature = "no_function"))] use rhai::{Dynamic, Engine, EvalAltResult, FnPtr, Module, RegisterFn, INT}; use std::any::TypeId; +use std::mem::take; #[test] fn test_fn_ptr_curry_call() -> Result<(), Box> { @@ -88,6 +89,29 @@ fn test_closures() -> Result<(), Box> { 42 ); + engine.register_raw_fn( + "custom_call", + &[TypeId::of::(), TypeId::of::()], + |engine: &Engine, module: &Module, args: &mut [&mut Dynamic]| { + let func = take(args[1]).cast::(); + + func.call_dynamic(engine, module, None, []) + }, + ); + + assert_eq!( + engine.eval::( + r#" + let a = 42.0; + let b = 0; + let f = || b.custom_call(|| a.to_int()); + + f.call() + "# + )?, + 42 + ); + Ok(()) } From 39ee74112c63ca7283e380b10cacd5cfc4de1f25 Mon Sep 17 00:00:00 2001 From: Ilya Lakhin Date: Sun, 9 Aug 2020 18:42:33 +0700 Subject: [PATCH 2/3] no-closure feature issue fixed --- src/parser.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/parser.rs b/src/parser.rs index a47f49e8..c16116a8 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1639,7 +1639,9 @@ fn parse_primary( // Function call Token::Identifier(s) if *next_token == Token::LeftParen || *next_token == Token::Bang => { // Once the identifier consumed we must enable next variables capturing - state.allow_capture = true; + #[cfg(not(feature = "no_closure"))] { + state.allow_capture = true; + } Expr::Variable(Box::new(((s, settings.pos), None, 0, None))) } // Normal variable access From d84ef1a0d11bc022a518bca5f9ac09e728bce631 Mon Sep 17 00:00:00 2001 From: Ilya Lakhin Date: Sun, 9 Aug 2020 18:55:01 +0700 Subject: [PATCH 3/3] CLosures test fix --- tests/closures.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/closures.rs b/tests/closures.rs index 66dad215..9d22fda3 100644 --- a/tests/closures.rs +++ b/tests/closures.rs @@ -102,9 +102,9 @@ fn test_closures() -> Result<(), Box> { assert_eq!( engine.eval::( r#" - let a = 42.0; + let a = 41; let b = 0; - let f = || b.custom_call(|| a.to_int()); + let f = || b.custom_call(|| a + 1); f.call() "#