Fix bug with optimizing op-assignment operators.

This commit is contained in:
Stephen Chung 2022-01-23 21:09:37 +08:00
parent 5c0cf70f70
commit 97be256a1a
5 changed files with 31 additions and 5 deletions

View File

@ -1,12 +1,13 @@
Rhai Release Notes Rhai Release Notes
================== ==================
Version 1.5.0 Version 1.4.1
============= =============
Bug fixes Bug fixes
--------- ---------
* Expressions such as `x = x + 1` no longer panics.
* Padding arrays with another array via `pad` no longer loops indefinitely. * Padding arrays with another array via `pad` no longer loops indefinitely.
* `chop` for arrays and BLOB's now works properly. * `chop` for arrays and BLOB's now works properly.
* `set_bit` for bit-flags with negative index now works correctly. * `set_bit` for bit-flags with negative index now works correctly.

View File

@ -45,7 +45,7 @@ impl OpAssignment<'_> {
#[must_use] #[must_use]
pub fn new_from_token(op: Token) -> Self { pub fn new_from_token(op: Token) -> Self {
let op_raw = op let op_raw = op
.map_op_assignment() .get_base_op_from_assignment()
.expect("op-assignment operator") .expect("op-assignment operator")
.literal_syntax(); .literal_syntax();
Self { Self {
@ -54,6 +54,26 @@ impl OpAssignment<'_> {
op: op.literal_syntax(), 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. /// _(internals)_ A scoped block of statements.

View File

@ -423,7 +423,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
match x.2 { match x.2 {
Expr::FnCall(ref mut x2, _) => { Expr::FnCall(ref mut x2, _) => {
state.set_dirty(); 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]); let value = mem::take(&mut x2.args[1]);

View File

@ -636,7 +636,7 @@ impl Token {
/// Get the corresponding operator of the token if it is an op-assignment operator. /// Get the corresponding operator of the token if it is an op-assignment operator.
#[must_use] #[must_use]
pub const fn map_op_assignment(&self) -> Option<Self> { pub const fn get_base_op_from_assignment(&self) -> Option<Self> {
Some(match self { Some(match self {
Self::PlusAssign => Self::Plus, Self::PlusAssign => Self::Plus,
Self::MinusAssign => Self::Minus, Self::MinusAssign => Self::Minus,
@ -675,7 +675,7 @@ impl Token {
/// Get the corresponding op-assignment operator of the token. /// Get the corresponding op-assignment operator of the token.
#[must_use] #[must_use]
pub const fn make_op_assignment(&self) -> Option<Self> { pub const fn convert_to_op_assignment(&self) -> Option<Self> {
Some(match self { Some(match self {
Self::Plus => Self::PlusAssign, Self::Plus => Self::PlusAssign,
Self::Minus => Self::MinusAssign, Self::Minus => Self::MinusAssign,

View File

@ -6,6 +6,11 @@ fn test_ops() -> Result<(), Box<EvalAltResult>> {
assert_eq!(engine.eval::<INT>("60 + 5")?, 65); assert_eq!(engine.eval::<INT>("60 + 5")?, 65);
assert_eq!(engine.eval::<INT>("(1 + 2) * (6 - 4) / 2")?, 3); assert_eq!(engine.eval::<INT>("(1 + 2) * (6 - 4) / 2")?, 3);
assert_eq!(engine.eval::<INT>("let x = 41; x = x + 1; x")?, 42);
assert_eq!(
engine.eval::<String>(r#"let s = "hello"; s = s + 42; s"#)?,
"hello42"
);
Ok(()) Ok(())
} }