Skip to content

Commit

Permalink
Fix negative zero sign erasure (#222)
Browse files Browse the repository at this point in the history
This avoids bugs were the evaluator was replacing `-0` results with
only `0`.
  • Loading branch information
jeparlefrancais authored Oct 21, 2024
1 parent 1752449 commit 9cbf20d
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 4 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Unreleased

* fix negative zero sign erasure ([#222](https://github.com/seaofvoices/darklua/pull/222))
* add `remove_if_expression` rule ([#221](https://github.com/seaofvoices/darklua/pull/221))

## 0.14.0
Expand Down
5 changes: 4 additions & 1 deletion src/nodes/expressions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,9 @@ impl From<f64> for Expression {
DecimalNumber::new(0.0),
)
.into(),
FpCategory::Zero => DecimalNumber::new(0.0).into(),
FpCategory::Zero => {
DecimalNumber::new(if value.is_sign_positive() { 0.0 } else { -0.0 }).into()
}
FpCategory::Subnormal | FpCategory::Normal => {
if value < 0.0 {
UnaryExpression::new(UnaryOperator::Minus, Expression::from(value.abs())).into()
Expand Down Expand Up @@ -346,6 +348,7 @@ mod test {
f64_1e42 => 1e42_f64,
f64_infinity => f64::INFINITY,
i64_minus_one => -1_i64,
f64_minus_zero => -0.0,
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
source: src/nodes/expressions/mod.rs
expression: result
---
Number(
Decimal(
DecimalNumber {
float: -0.0,
exponent: None,
token: None,
},
),
)
16 changes: 16 additions & 0 deletions src/process/evaluator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,7 @@ mod test {
false_expression(Expression::from(false)) => LuaValue::False,
nil_expression(Expression::nil()) => LuaValue::Nil,
number_expression(DecimalNumber::new(0.0)) => LuaValue::Number(0.0),
number_expression_negative_zero(DecimalNumber::new(-0.0)) => LuaValue::Number(-0.0),
string_expression(StringExpression::from_value("foo")) => LuaValue::String("foo".to_owned()),
empty_interpolated_string_expression(InterpolatedStringExpression::empty()) => LuaValue::String("".to_owned()),
interpolated_string_expression_with_one_string(InterpolatedStringExpression::empty().with_segment("hello"))
Expand Down Expand Up @@ -550,6 +551,10 @@ mod test {
(expect_float - result).abs() < f64::EPSILON,
"{} does not approximate {}", result, expect_float
);
assert!(
expect_float.is_sign_positive() == result.is_sign_positive(),
"{} should be of the same sign as {}", result, expect_float
);
}
}
_ => {
Expand Down Expand Up @@ -667,6 +672,16 @@ mod test {
Expression::from(1.0),
Expression::from(0.0)
) => LuaValue::Number(f64::INFINITY),
negative_zero_plus_negative_zero(
BinaryOperator::Plus,
Expression::from(-0.0),
Expression::from(-0.0)
) => LuaValue::Number(-0.0),
negative_zero_minus_zero(
BinaryOperator::Minus,
Expression::from(-0.0),
Expression::from(0.0)
) => LuaValue::Number(-0.0),
zero_divided_by_zero(
BinaryOperator::Slash,
Expression::from(0.0),
Expand Down Expand Up @@ -1038,6 +1053,7 @@ mod test {
) => LuaValue::False,
not_identifier(Not, Expression::identifier("foo")) => LuaValue::Unknown,
minus_one(Minus, DecimalNumber::new(1.0)) => LuaValue::from(-1.0),
minus_zero(Minus, DecimalNumber::new(-0.0)) => LuaValue::from(-0.0),
minus_negative_number(Minus, DecimalNumber::new(-5.0)) => LuaValue::from(5.0),
minus_string_converted_to_number(Minus, StringExpression::from_value("1")) => LuaValue::from(-1.0)
);
Expand Down
10 changes: 7 additions & 3 deletions tests/rule_tests/compute_expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,15 @@ test_rule!(
=> "return 'is equal'",
if_expression_elseif_always_false("return if false then 'is true' elseif 1 == 2 then 'is equal' else nil")
=> "return nil",
preserve_negative_zero("return -0") => "return -0",
addition_preserve_negative_zero("return -0 + -0") => "return -0",
subtract_preserve_negative_zero("return -0 - 0") => "return -0",
);

test_rule_without_effects!(if_expression_unknown_condition(
"return if condition then func() else func2()"
),);
test_rule_without_effects!(
ComputeExpression::default(),
if_expression_unknown_condition("return if condition then func() else func2()"),
);

#[test]
fn deserialize_from_object_notation() {
Expand Down

0 comments on commit 9cbf20d

Please sign in to comment.