diff --git a/CHANGELOG.md b/CHANGELOG.md index c03a5106..24034e1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,13 @@ Rhai Release Notes ================== -Version 1.5.0 +Version 1.4.1 ============= Bug fixes --------- +* Expressions such as `x = x + 1` no longer panics. * Padding arrays with another array via `pad` no longer loops indefinitely. * `chop` for arrays and BLOB's now works properly. * `set_bit` for bit-flags with negative index now works correctly. diff --git a/src/ast/stmt.rs b/src/ast/stmt.rs index a4580c1b..136356a1 100644 --- a/src/ast/stmt.rs +++ b/src/ast/stmt.rs @@ -45,7 +45,7 @@ impl OpAssignment<'_> { #[must_use] pub fn new_from_token(op: Token) -> Self { let op_raw = op - .map_op_assignment() + .get_base_op_from_assignment() .expect("op-assignment operator") .literal_syntax(); Self { @@ -54,6 +54,26 @@ impl OpAssignment<'_> { op: op.literal_syntax(), } } + /// Create a new [`OpAssignment`] from a base operator. + /// + /// # Panics + /// + /// Panics if the name is not an operator that can be converted into an op-operator. + #[must_use] + #[inline(always)] + pub fn new_from_base(name: &str) -> Self { + Self::new_from_base_token(Token::lookup_from_syntax(name).expect("operator")) + } + /// Convert a [`Token`] into a new [`OpAssignment`]. + /// + /// # Panics + /// + /// Panics if the token is cannot be converted into an op-assignment operator. + #[inline(always)] + #[must_use] + pub fn new_from_base_token(op: Token) -> Self { + Self::new_from_token(op.convert_to_op_assignment().expect("operator")) + } } /// _(internals)_ A scoped block of statements. diff --git a/src/optimizer.rs b/src/optimizer.rs index 0244f8cf..7bfe8bbf 100644 --- a/src/optimizer.rs +++ b/src/optimizer.rs @@ -423,7 +423,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b match x.2 { Expr::FnCall(ref mut x2, _) => { state.set_dirty(); - x.1 = Some(OpAssignment::new(&x2.name)); + x.1 = Some(OpAssignment::new_from_base(&x2.name)); let value = mem::take(&mut x2.args[1]); diff --git a/src/tokenizer.rs b/src/tokenizer.rs index e82997ac..b23c630e 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -636,7 +636,7 @@ impl Token { /// Get the corresponding operator of the token if it is an op-assignment operator. #[must_use] - pub const fn map_op_assignment(&self) -> Option { + pub const fn get_base_op_from_assignment(&self) -> Option { Some(match self { Self::PlusAssign => Self::Plus, Self::MinusAssign => Self::Minus, @@ -675,7 +675,7 @@ impl Token { /// Get the corresponding op-assignment operator of the token. #[must_use] - pub const fn make_op_assignment(&self) -> Option { + pub const fn convert_to_op_assignment(&self) -> Option { Some(match self { Self::Plus => Self::PlusAssign, Self::Minus => Self::MinusAssign, diff --git a/tests/ops.rs b/tests/ops.rs index d50bf517..df5be33c 100644 --- a/tests/ops.rs +++ b/tests/ops.rs @@ -6,6 +6,11 @@ fn test_ops() -> Result<(), Box> { assert_eq!(engine.eval::("60 + 5")?, 65); assert_eq!(engine.eval::("(1 + 2) * (6 - 4) / 2")?, 3); + assert_eq!(engine.eval::("let x = 41; x = x + 1; x")?, 42); + assert_eq!( + engine.eval::(r#"let s = "hello"; s = s + 42; s"#)?, + "hello42" + ); Ok(()) }