diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b8e8aac..37515af0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ Rhai Release Notes Version 1.1.0 ============= +Bug fixes +--------- + +* Custom syntax starting with a disabled standard keyword now works properly. + Enhancements ------------ @@ -16,6 +21,7 @@ Enhancements * `parse_float()`, `PI()` and `E()` now defer to `Decimal` under `no_float` if `decimal` is turned on. * Added `log10()` for `Decimal`. * `ln` for `Decimal` is now checked and won't panic. +* `Scope::set_value` now takes anything that implements `Into>`. Version 1.0.2 diff --git a/src/custom_syntax.rs b/src/custom_syntax.rs index 5325d98b..be4a22e7 100644 --- a/src/custom_syntax.rs +++ b/src/custom_syntax.rs @@ -230,11 +230,10 @@ impl Engine { } s.into() } - // Standard keyword in first position - s if segments.is_empty() - && token - .as_ref() - .map_or(false, |v| v.is_standard_keyword() || v.is_reserved()) => + // Standard keyword in first position but not disabled + _ if segments.is_empty() + && token.as_ref().map_or(false, |v| v.is_standard_keyword()) + && !self.disabled_symbols.contains(s) => { return Err(LexError::ImproperSymbol( s.to_string(), @@ -247,13 +246,13 @@ impl Engine { .into_err(Position::NONE)); } // Identifier in first position - s if segments.is_empty() && is_valid_identifier(s.chars()) => { + _ if segments.is_empty() && is_valid_identifier(s.chars()) => { // Make it a custom keyword/symbol if it is disabled or reserved - if (self.disabled_symbols.contains(s) - || matches!(token, Some(Token::Reserved(_)))) - && !self.custom_keywords.contains_key(s) + if self.disabled_symbols.contains(s) || token.map_or(false, |v| v.is_reserved()) { - self.custom_keywords.insert(s.into(), None); + if !self.custom_keywords.contains_key(s) { + self.custom_keywords.insert(s.into(), None); + } } s.into() } diff --git a/tests/custom_syntax.rs b/tests/custom_syntax.rs index a2ba015e..32832332 100644 --- a/tests/custom_syntax.rs +++ b/tests/custom_syntax.rs @@ -1,5 +1,5 @@ use rhai::{ - Dynamic, Engine, EvalAltResult, ImmutableString, LexError, ParseErrorType, Position, INT, + Dynamic, Engine, EvalAltResult, ImmutableString, LexError, ParseErrorType, Position, Scope, INT, }; #[test] @@ -146,6 +146,42 @@ fn test_custom_syntax() -> Result<(), Box> { assert_eq!(engine.eval::("test2 } 42")?, 42); assert_eq!(engine.eval::("test3; 42")?, 42); + // Register the custom syntax: var x = ??? + engine.register_custom_syntax( + &["var", "$ident$", "=", "$expr$"], + true, + |context, inputs| { + let var_name = inputs[0].get_variable_name().unwrap().to_string(); + let expr = &inputs[1]; + + // Evaluate the expression + let value = context.eval_expression_tree(expr)?; + + // Push new variable into the scope if it doesn't already exist. + // Otherwise set its value. + // WARNING - This panics if 'var_name' already exists and is constant! + // - In a real implementation, check this before doing anything! + context.scope_mut().set_value(var_name, value); + + Ok(Dynamic::UNIT) + }, + )?; + + let mut scope = Scope::new(); + + assert_eq!( + engine.eval_with_scope::(&mut scope, "var foo = 42; foo")?, + 42 + ); + assert_eq!(scope.get_value::("foo"), Some(42)); + assert_eq!(scope.len(), 1); + assert_eq!( + engine.eval_with_scope::(&mut scope, "var foo = 123; foo")?, + 123 + ); + assert_eq!(scope.get_value::("foo"), Some(123)); + assert_eq!(scope.len(), 1); + Ok(()) }