Fix bug in custom syntax starting with disabled stardard keyword.

This commit is contained in:
Stephen Chung 2021-08-13 19:23:20 +08:00
parent c1b4c81e75
commit 114c93f430
3 changed files with 52 additions and 11 deletions

View File

@ -4,6 +4,11 @@ Rhai Release Notes
Version 1.1.0 Version 1.1.0
============= =============
Bug fixes
---------
* Custom syntax starting with a disabled standard keyword now works properly.
Enhancements Enhancements
------------ ------------
@ -16,6 +21,7 @@ Enhancements
* `parse_float()`, `PI()` and `E()` now defer to `Decimal` under `no_float` if `decimal` is turned on. * `parse_float()`, `PI()` and `E()` now defer to `Decimal` under `no_float` if `decimal` is turned on.
* Added `log10()` for `Decimal`. * Added `log10()` for `Decimal`.
* `ln` for `Decimal` is now checked and won't panic. * `ln` for `Decimal` is now checked and won't panic.
* `Scope::set_value` now takes anything that implements `Into<Cow<str>>`.
Version 1.0.2 Version 1.0.2

View File

@ -230,11 +230,10 @@ impl Engine {
} }
s.into() s.into()
} }
// Standard keyword in first position // Standard keyword in first position but not disabled
s if segments.is_empty() _ if segments.is_empty()
&& token && token.as_ref().map_or(false, |v| v.is_standard_keyword())
.as_ref() && !self.disabled_symbols.contains(s) =>
.map_or(false, |v| v.is_standard_keyword() || v.is_reserved()) =>
{ {
return Err(LexError::ImproperSymbol( return Err(LexError::ImproperSymbol(
s.to_string(), s.to_string(),
@ -247,13 +246,13 @@ impl Engine {
.into_err(Position::NONE)); .into_err(Position::NONE));
} }
// Identifier in first position // 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 // Make it a custom keyword/symbol if it is disabled or reserved
if (self.disabled_symbols.contains(s) if self.disabled_symbols.contains(s) || token.map_or(false, |v| v.is_reserved())
|| matches!(token, Some(Token::Reserved(_))))
&& !self.custom_keywords.contains_key(s)
{ {
self.custom_keywords.insert(s.into(), None); if !self.custom_keywords.contains_key(s) {
self.custom_keywords.insert(s.into(), None);
}
} }
s.into() s.into()
} }

View File

@ -1,5 +1,5 @@
use rhai::{ use rhai::{
Dynamic, Engine, EvalAltResult, ImmutableString, LexError, ParseErrorType, Position, INT, Dynamic, Engine, EvalAltResult, ImmutableString, LexError, ParseErrorType, Position, Scope, INT,
}; };
#[test] #[test]
@ -146,6 +146,42 @@ fn test_custom_syntax() -> Result<(), Box<EvalAltResult>> {
assert_eq!(engine.eval::<INT>("test2 } 42")?, 42); assert_eq!(engine.eval::<INT>("test2 } 42")?, 42);
assert_eq!(engine.eval::<INT>("test3; 42")?, 42); assert_eq!(engine.eval::<INT>("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::<INT>(&mut scope, "var foo = 42; foo")?,
42
);
assert_eq!(scope.get_value::<INT>("foo"), Some(42));
assert_eq!(scope.len(), 1);
assert_eq!(
engine.eval_with_scope::<INT>(&mut scope, "var foo = 123; foo")?,
123
);
assert_eq!(scope.get_value::<INT>("foo"), Some(123));
assert_eq!(scope.len(), 1);
Ok(()) Ok(())
} }