Skip to main content

palladium/optimizer/
simplify.rs

1//! Expression simplification pass
2//!
3//! This pass simplifies expressions by removing redundant operations
4//! and unnecessary parentheses in the generated code
5
6use crate::ast::*;
7use crate::errors::{CompileError, Span};
8use crate::optimizer::OptimizationPass;
9
10pub struct SimplificationPass {
11    changes_made: usize,
12}
13
14impl Default for SimplificationPass {
15    fn default() -> Self {
16        Self::new()
17    }
18}
19
20impl SimplificationPass {
21    pub fn new() -> Self {
22        Self { changes_made: 0 }
23    }
24}
25
26impl OptimizationPass for SimplificationPass {
27    fn name(&self) -> &str {
28        "Expression Simplification"
29    }
30
31    fn optimize_program(&mut self, program: &mut Program) -> Result<bool, CompileError> {
32        self.changes_made = 0;
33
34        for item in &mut program.items {
35            if let Item::Function(func) = item {
36                self.optimize_function(func)?;
37            }
38        }
39
40        Ok(self.changes_made > 0)
41    }
42
43    fn optimize_statement(&mut self, stmt: &mut Stmt) -> Result<bool, CompileError> {
44        match stmt {
45            Stmt::Let { value, .. } => {
46                self.optimize_expression(value)?;
47            }
48            Stmt::Expr(expr) => {
49                self.optimize_expression(expr)?;
50            }
51            Stmt::If {
52                condition,
53                then_branch,
54                else_branch,
55                ..
56            } => {
57                self.optimize_expression(condition)?;
58
59                for stmt in then_branch {
60                    self.optimize_statement(stmt)?;
61                }
62
63                if let Some(else_branch) = else_branch {
64                    for stmt in else_branch {
65                        self.optimize_statement(stmt)?;
66                    }
67                }
68            }
69            Stmt::While {
70                condition, body, ..
71            } => {
72                self.optimize_expression(condition)?;
73
74                for stmt in body {
75                    self.optimize_statement(stmt)?;
76                }
77            }
78            Stmt::Return(Some(expr)) => {
79                self.optimize_expression(expr)?;
80            }
81            Stmt::Return(None) => {}
82            Stmt::Assign { value, .. } => {
83                self.optimize_expression(value)?;
84            }
85            _ => {}
86        }
87
88        Ok(false)
89    }
90
91    fn optimize_expression(&mut self, expr: &mut Expr) -> Result<bool, CompileError> {
92        match expr {
93            Expr::Binary {
94                left, op, right, ..
95            } => {
96                // Optimize sub-expressions first
97                self.optimize_expression(left)?;
98                self.optimize_expression(right)?;
99
100                // Simplify boolean comparisons
101                match (left.as_ref(), *op, right.as_ref()) {
102                    // x == true => x
103                    (_, BinOp::Eq, Expr::Bool(true)) => {
104                        *expr = left.as_ref().clone();
105                        self.changes_made += 1;
106                        return Ok(true);
107                    }
108                    // true == x => x
109                    (Expr::Bool(true), BinOp::Eq, _) => {
110                        *expr = right.as_ref().clone();
111                        self.changes_made += 1;
112                        return Ok(true);
113                    }
114                    // x == false => !x
115                    (_, BinOp::Eq, Expr::Bool(false)) => {
116                        *expr = Expr::Unary {
117                            op: UnaryOp::Not,
118                            operand: left.clone(),
119                            span: Span::dummy(),
120                        };
121                        self.changes_made += 1;
122                        return Ok(true);
123                    }
124                    // false == x => !x
125                    (Expr::Bool(false), BinOp::Eq, _) => {
126                        *expr = Expr::Unary {
127                            op: UnaryOp::Not,
128                            operand: right.clone(),
129                            span: Span::dummy(),
130                        };
131                        self.changes_made += 1;
132                        return Ok(true);
133                    }
134                    // x != false => x
135                    (_, BinOp::Ne, Expr::Bool(false)) => {
136                        *expr = left.as_ref().clone();
137                        self.changes_made += 1;
138                        return Ok(true);
139                    }
140                    // false != x => x
141                    (Expr::Bool(false), BinOp::Ne, _) => {
142                        *expr = right.as_ref().clone();
143                        self.changes_made += 1;
144                        return Ok(true);
145                    }
146                    // x != true => !x
147                    (_, BinOp::Ne, Expr::Bool(true)) => {
148                        *expr = Expr::Unary {
149                            op: UnaryOp::Not,
150                            operand: left.clone(),
151                            span: Span::dummy(),
152                        };
153                        self.changes_made += 1;
154                        return Ok(true);
155                    }
156                    // true != x => !x
157                    (Expr::Bool(true), BinOp::Ne, _) => {
158                        *expr = Expr::Unary {
159                            op: UnaryOp::Not,
160                            operand: right.clone(),
161                            span: Span::dummy(),
162                        };
163                        self.changes_made += 1;
164                        return Ok(true);
165                    }
166                    _ => {}
167                }
168
169                // Simplify double negation patterns
170                match (left.as_ref(), *op, right.as_ref()) {
171                    // !(x == y) => x != y
172                    (
173                        Expr::Unary {
174                            op: UnaryOp::Not,
175                            operand,
176                            ..
177                        },
178                        BinOp::Eq,
179                        _,
180                    ) => {
181                        if let Expr::Binary {
182                            left: l,
183                            op: BinOp::Eq,
184                            right: r,
185                            ..
186                        } = operand.as_ref()
187                        {
188                            *expr = Expr::Binary {
189                                left: l.clone(),
190                                op: BinOp::Ne,
191                                right: r.clone(),
192                                span: Span::dummy(),
193                            };
194                            self.changes_made += 1;
195                            return Ok(true);
196                        }
197                    }
198                    _ => {}
199                }
200            }
201            Expr::Unary { op, operand, .. } => {
202                self.optimize_expression(operand)?;
203
204                // Simplify double negation: !!x => x
205                if let UnaryOp::Not = op {
206                    if let Expr::Unary {
207                        op: UnaryOp::Not,
208                        operand: inner,
209                        ..
210                    } = operand.as_ref()
211                    {
212                        *expr = inner.as_ref().clone();
213                        self.changes_made += 1;
214                        return Ok(true);
215                    }
216                }
217            }
218            Expr::Call { args, .. } => {
219                for arg in args {
220                    self.optimize_expression(arg)?;
221                }
222            }
223            Expr::Index { array, index, .. } => {
224                self.optimize_expression(array)?;
225                self.optimize_expression(index)?;
226            }
227            Expr::FieldAccess { object, .. } => {
228                self.optimize_expression(object)?;
229            }
230            Expr::ArrayLiteral { elements, .. } => {
231                for elem in elements {
232                    self.optimize_expression(elem)?;
233                }
234            }
235            _ => {}
236        }
237
238        Ok(false)
239    }
240}