1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
use super::Simplify;
use toasty_core::stmt::{self, Expr};
impl Simplify<'_> {
pub(super) fn simplify_expr_not(&mut self, expr_not: &mut stmt::ExprNot) -> Option<Expr> {
// Double negation elimination, `not(not(x))` → `x`
if let Expr::Not(inner) = expr_not.expr.as_mut() {
return Some(inner.expr.take());
}
// Constant folding,
//
// - `not(true)` → `false`
// - `not(false)` → `true`
// - `not(null)` → `null`
match expr_not.expr.as_ref() {
Expr::Value(stmt::Value::Bool(b)) => {
return Some(Expr::Value(stmt::Value::Bool(!b)));
}
Expr::Value(stmt::Value::Null) => {
return Some(Expr::null());
}
_ => {}
}
// Negation of comparisons, `not(x = y)` → `x != y`, etc.
if let Expr::BinaryOp(binary_op) = expr_not.expr.as_mut()
&& let Some(negated_op) = binary_op.op.negate()
{
binary_op.op = negated_op;
return Some(expr_not.expr.take());
}
// De Morgan's law, `not(a and b)` → `not(a) or not(b)`
if let Expr::And(expr_and) = expr_not.expr.as_mut() {
let negated = expr_and
.operands
.drain(..)
.map(Expr::not)
.collect::<Vec<_>>();
return Some(Expr::or_from_vec(negated));
}
// De Morgan's law, `not(a or b)` → `not(a) and not(b)`
if let Expr::Or(expr_or) = expr_not.expr.as_mut() {
let negated = expr_or
.operands
.drain(..)
.map(Expr::not)
.collect::<Vec<_>>();
return Some(Expr::and_from_vec(negated));
}
// `not(x in ())` → `true` (x NOT IN empty list is always true)
if let Expr::InList(expr_in_list) = expr_not.expr.as_ref()
&& expr_in_list.list.is_list_empty()
{
return Some(true.into());
}
None
}
}