snix_eval/compiler/
optimiser.rs1use super::*;
5
6use ast::Expr;
7
8pub(super) fn optimise_expr(c: &mut Compiler, slot: LocalIdx, expr: ast::Expr) -> ast::Expr {
10 match expr {
11 Expr::BinOp(_) => optimise_bin_op(c, slot, expr),
12 _ => expr,
13 }
14}
15
16enum LitBool {
17 Expr(Expr),
18 True(Expr),
19 False(Expr),
20}
21
22fn is_lit_bool(expr: ast::Expr) -> LitBool {
24 if let ast::Expr::Ident(ident) = &expr {
25 match ident.ident_token().unwrap().text() {
26 "true" => LitBool::True(expr),
27 "false" => LitBool::False(expr),
28 _ => LitBool::Expr(expr),
29 }
30 } else {
31 LitBool::Expr(expr)
32 }
33}
34
35fn optimise_bin_op(c: &mut Compiler, slot: LocalIdx, expr: ast::Expr) -> ast::Expr {
37 use ast::BinOpKind;
38
39 if c.is_user_defined("true") || c.is_user_defined("false") {
43 return expr;
44 }
45
46 if let Expr::BinOp(op) = &expr {
47 let lhs = is_lit_bool(op.lhs().unwrap());
48 let rhs = is_lit_bool(op.rhs().unwrap());
49
50 match (op.operator().unwrap(), lhs, rhs) {
51 (BinOpKind::Or, LitBool::False(f), LitBool::Expr(other))
53 | (BinOpKind::Or, LitBool::Expr(other), LitBool::False(f)) => {
54 c.emit_warning(
55 &f,
56 WarningKind::UselessBoolOperation(
57 "this `false` has no effect on the result of the comparison",
58 ),
59 );
60
61 return other;
62 }
63
64 (BinOpKind::And, LitBool::True(t), LitBool::Expr(other))
66 | (BinOpKind::And, LitBool::Expr(other), LitBool::True(t)) => {
67 c.emit_warning(
68 &t,
69 WarningKind::UselessBoolOperation(
70 "this `true` has no effect on the result of the comparison",
71 ),
72 );
73
74 return other;
75 }
76
77 (BinOpKind::Or, LitBool::True(t), LitBool::Expr(other)) => {
80 c.emit_warning(
81 op,
82 WarningKind::UselessBoolOperation("this expression is always true"),
83 );
84
85 c.compile_dead_code(slot, other);
86
87 return t;
88 }
89
90 (BinOpKind::Or, _, LitBool::True(t)) | (BinOpKind::Or, LitBool::True(t), _) => {
91 c.emit_warning(
92 op,
93 WarningKind::UselessBoolOperation("this expression is always true"),
94 );
95
96 return t;
97 }
98
99 (BinOpKind::And, LitBool::False(f), LitBool::Expr(other)) => {
101 c.emit_warning(
102 op,
103 WarningKind::UselessBoolOperation("this expression is always false"),
104 );
105
106 c.compile_dead_code(slot, other);
107
108 return f;
109 }
110
111 (BinOpKind::And, _, LitBool::False(f)) | (BinOpKind::Or, LitBool::False(f), _) => {
112 c.emit_warning(
113 op,
114 WarningKind::UselessBoolOperation("this expression is always false"),
115 );
116
117 return f;
118 }
119
120 _ => { }
121 }
122 }
123
124 expr
125}