Allow module access in closures.

This commit is contained in:
Stephen Chung 2020-08-22 22:44:24 +08:00
parent 0b04d05afe
commit 0ece75aba3
4 changed files with 32 additions and 2 deletions

View File

@ -1,6 +1,6 @@
[package] [package]
name = "rhai" name = "rhai"
version = "0.19.0" version = "0.18.3"
edition = "2018" edition = "2018"
authors = ["Jonathan Turner", "Lukáš Hozda", "Stephen Chung"] authors = ["Jonathan Turner", "Lukáš Hozda", "Stephen Chung"]
description = "Embedded scripting for Rust" description = "Embedded scripting for Rust"

View File

@ -1,13 +1,14 @@
Rhai Release Notes Rhai Release Notes
================== ==================
Version 0.19.0 Version 0.18.3
============== ==============
Bug fixes Bug fixes
--------- ---------
* `Engine::compile_expression`, `Engine::eval_expression` etc. no longer parse anonymous functions and closures. * `Engine::compile_expression`, `Engine::eval_expression` etc. no longer parse anonymous functions and closures.
* Imported modules now work inside closures.
Version 0.18.2 Version 0.18.2

View File

@ -1645,11 +1645,22 @@ fn parse_primary(
} }
Expr::Variable(Box::new(((s, settings.pos), None, 0, None))) Expr::Variable(Box::new(((s, settings.pos), None, 0, None)))
} }
// Module qualification
#[cfg(not(feature = "no_module"))]
Token::Identifier(s) if *next_token == Token::DoubleColon => {
// Once the identifier consumed we must enable next variables capturing
#[cfg(not(feature = "no_closure"))]
{
state.allow_capture = true;
}
Expr::Variable(Box::new(((s, settings.pos), None, 0, None)))
}
// Normal variable access // Normal variable access
Token::Identifier(s) => { Token::Identifier(s) => {
let index = state.access_var(&s, settings.pos); let index = state.access_var(&s, settings.pos);
Expr::Variable(Box::new(((s, settings.pos), None, 0, index))) Expr::Variable(Box::new(((s, settings.pos), None, 0, index)))
} }
// Function call is allowed to have reserved keyword // Function call is allowed to have reserved keyword
Token::Reserved(s) if *next_token == Token::LeftParen || *next_token == Token::Bang => { Token::Reserved(s) if *next_token == Token::LeftParen || *next_token == Token::Bang => {
if is_keyword_function(&s) { if is_keyword_function(&s) {
@ -1658,6 +1669,7 @@ fn parse_primary(
return Err(PERR::Reserved(s).into_err(settings.pos)); return Err(PERR::Reserved(s).into_err(settings.pos));
} }
} }
// Access to `this` as a variable is OK // Access to `this` as a variable is OK
Token::Reserved(s) if s == KEYWORD_THIS && *next_token != Token::LeftParen => { Token::Reserved(s) if s == KEYWORD_THIS && *next_token != Token::LeftParen => {
if !settings.is_function_scope { if !settings.is_function_scope {
@ -1669,9 +1681,11 @@ fn parse_primary(
Expr::Variable(Box::new(((s, settings.pos), None, 0, None))) Expr::Variable(Box::new(((s, settings.pos), None, 0, None)))
} }
} }
Token::Reserved(s) if is_valid_identifier(s.chars()) => { Token::Reserved(s) if is_valid_identifier(s.chars()) => {
return Err(PERR::Reserved(s).into_err(settings.pos)); return Err(PERR::Reserved(s).into_err(settings.pos));
} }
Token::LeftParen => parse_paren_expr(input, state, lib, settings.level_up())?, Token::LeftParen => parse_paren_expr(input, state, lib, settings.level_up())?,
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
Token::LeftBracket => parse_array_literal(input, state, lib, settings.level_up())?, Token::LeftBracket => parse_array_literal(input, state, lib, settings.level_up())?,
@ -1680,6 +1694,7 @@ fn parse_primary(
Token::True => Expr::True(settings.pos), Token::True => Expr::True(settings.pos),
Token::False => Expr::False(settings.pos), Token::False => Expr::False(settings.pos),
Token::LexError(err) => return Err(err.into_err(settings.pos)), Token::LexError(err) => return Err(err.into_err(settings.pos)),
_ => { _ => {
return Err( return Err(
PERR::BadInput(format!("Unexpected '{}'", token.syntax())).into_err(settings.pos) PERR::BadInput(format!("Unexpected '{}'", token.syntax())).into_err(settings.pos)

View File

@ -120,6 +120,20 @@ fn test_fn_ptr_raw() -> Result<(), Box<EvalAltResult>> {
42 42
); );
assert_eq!(
engine.eval::<INT>(
r#"
fn foo(x, y) { this += x + y; }
let x = 40;
let v = 1;
x.bar(Fn("foo").curry(v), 1);
x
"#
)?,
42
);
assert!(matches!( assert!(matches!(
*engine.eval::<INT>( *engine.eval::<INT>(
r#" r#"