Skip to main content

nargo_ir/
optimizer.rs

1#![warn(missing_docs)]
2
3//! 优化器模块
4//! 
5//! 提供 IR 结构的优化功能,包括常量折叠、死代码消除等优化规则。
6
7use nargo_types::NargoValue;
8
9use crate::expr::JsExpr;
10use crate::program::{IRModule, JsProgram};
11use crate::stmt::JsStmt;
12use crate::types::Trivia;
13use nargo_types::Span;
14
15/// 表达式优化器
16///
17/// 负责优化 JavaScript 表达式,包括常量折叠等优化规则。
18pub struct ExprOptimizer;
19
20impl ExprOptimizer {
21    /// 优化表达式
22    ///
23    /// # Parameters
24    /// - `expr`: 要优化的表达式
25    pub fn optimize(expr: &mut JsExpr) {
26        match expr {
27            JsExpr::Unary { op, argument, .. } => {
28                Self::optimize(argument);
29                // 常量折叠:一元表达式
30                if let JsExpr::Literal(value, span, trivia) = &**argument {
31                    match op.as_str() {
32                        "!" => {
33                            if let Some(b) = value.as_bool() {
34                                *expr = JsExpr::Literal(NargoValue::Bool(!b), *span, trivia.clone());
35                            }
36                        }
37                        "-" => {
38                            if let Some(n) = value.as_number() {
39                                *expr = JsExpr::Literal(NargoValue::Number(-n), *span, trivia.clone());
40                            }
41                        }
42                        "+" => {
43                            if let Some(n) = value.as_number() {
44                                *expr = JsExpr::Literal(NargoValue::Number(n), *span, trivia.clone());
45                            }
46                            else if let Some(s) = value.as_str() {
47                                if let Ok(n) = s.parse::<f64>() {
48                                    *expr = JsExpr::Literal(NargoValue::Number(n), *span, trivia.clone());
49                                }
50                            }
51                        }
52                        "~" => {
53                            if let Some(n) = value.as_number() {
54                                let int_val = n as i64;
55                                *expr = JsExpr::Literal(NargoValue::Number((!int_val) as f64), *span, trivia.clone());
56                            }
57                        }
58                        _ => return,
59                    };
60                }
61            }
62            JsExpr::Binary { left, op, right, span, trivia } => {
63                Self::optimize(left);
64                Self::optimize(right);
65                // 常量折叠:二元表达式
66                if let (JsExpr::Literal(left_val, _, _), JsExpr::Literal(right_val, _, _)) = (&**left, &**right) {
67                    match op.as_str() {
68                        "+" => {
69                            if let (Some(l), Some(r)) = (left_val.as_number(), right_val.as_number()) {
70                                *expr = JsExpr::Literal(NargoValue::Number(l + r), *span, trivia.clone());
71                            }
72                            else if let (Some(l), Some(r)) = (left_val.as_str(), right_val.as_str()) {
73                                *expr = JsExpr::Literal(NargoValue::String(format!("{}{}", l, r)), *span, trivia.clone());
74                            }
75                            else if let (Some(l), Some(r)) = (left_val.as_str(), right_val.as_number()) {
76                                *expr = JsExpr::Literal(NargoValue::String(format!("{}{}", l, r)), *span, trivia.clone());
77                            }
78                            else if let (Some(l), Some(r)) = (left_val.as_number(), right_val.as_str()) {
79                                *expr = JsExpr::Literal(NargoValue::String(format!("{}{}", l, r)), *span, trivia.clone());
80                            }
81                        }
82                        "-" => {
83                            if let (Some(l), Some(r)) = (left_val.as_number(), right_val.as_number()) {
84                                *expr = JsExpr::Literal(NargoValue::Number(l - r), *span, trivia.clone());
85                            }
86                        }
87                        "*" => {
88                            if let (Some(l), Some(r)) = (left_val.as_number(), right_val.as_number()) {
89                                *expr = JsExpr::Literal(NargoValue::Number(l * r), *span, trivia.clone());
90                            }
91                        }
92                        "/" => {
93                            if let (Some(l), Some(r)) = (left_val.as_number(), right_val.as_number()) {
94                                *expr = JsExpr::Literal(NargoValue::Number(l / r), *span, trivia.clone());
95                            }
96                        }
97                        "%" => {
98                            if let (Some(l), Some(r)) = (left_val.as_number(), right_val.as_number()) {
99                                *expr = JsExpr::Literal(NargoValue::Number(l % r), *span, trivia.clone());
100                            }
101                        }
102                        "==" | "!=" | "===" | "!==" => {
103                            let result = left_val == right_val;
104                            let final_result = if op == "!=" || op == "!==" { !result } else { result };
105                            *expr = JsExpr::Literal(NargoValue::Bool(final_result), *span, trivia.clone());
106                        }
107                        "<" => {
108                            if let (Some(l), Some(r)) = (left_val.as_number(), right_val.as_number()) {
109                                *expr = JsExpr::Literal(NargoValue::Bool(l < r), *span, trivia.clone());
110                            }
111                        }
112                        "<=" => {
113                            if let (Some(l), Some(r)) = (left_val.as_number(), right_val.as_number()) {
114                                *expr = JsExpr::Literal(NargoValue::Bool(l <= r), *span, trivia.clone());
115                            }
116                        }
117                        ">" => {
118                            if let (Some(l), Some(r)) = (left_val.as_number(), right_val.as_number()) {
119                                *expr = JsExpr::Literal(NargoValue::Bool(l > r), *span, trivia.clone());
120                            }
121                        }
122                        ">=" => {
123                            if let (Some(l), Some(r)) = (left_val.as_number(), right_val.as_number()) {
124                                *expr = JsExpr::Literal(NargoValue::Bool(l >= r), *span, trivia.clone());
125                            }
126                        }
127                        "&&" => {
128                            if let (Some(l), Some(r)) = (left_val.as_bool(), right_val.as_bool()) {
129                                *expr = JsExpr::Literal(NargoValue::Bool(l && r), *span, trivia.clone());
130                            }
131                        }
132                        "||" => {
133                            if let (Some(l), Some(r)) = (left_val.as_bool(), right_val.as_bool()) {
134                                *expr = JsExpr::Literal(NargoValue::Bool(l || r), *span, trivia.clone());
135                            }
136                        }
137                        _ => return,
138                    };
139                }
140            }
141            JsExpr::Conditional { test, consequent, alternate, span: _, trivia: _ } => {
142                Self::optimize(test);
143                Self::optimize(consequent);
144                Self::optimize(alternate);
145                // 常量折叠:条件表达式
146                if let JsExpr::Literal(test_val, _, _) = &**test {
147                    if let Some(b) = test_val.as_bool() {
148                        let optimized = if b { consequent.clone() } else { alternate.clone() };
149                        *expr = *optimized;
150                    }
151                }
152            }
153            JsExpr::Array(items, ..) => {
154                for item in items {
155                    Self::optimize(item);
156                }
157            }
158            JsExpr::Object(props, ..) => {
159                for (_, value) in props {
160                    Self::optimize(value);
161                }
162            }
163            JsExpr::Call { callee, args, .. } => {
164                Self::optimize(callee);
165                for arg in args {
166                    Self::optimize(arg);
167                }
168            }
169            JsExpr::Member { object, property, .. } => {
170                Self::optimize(object);
171                Self::optimize(property);
172            }
173            JsExpr::OptionalMember { object, property, .. } => {
174                Self::optimize(object);
175                Self::optimize(property);
176            }
177            JsExpr::OptionalCall { callee, args, .. } => {
178                Self::optimize(callee);
179                for arg in args {
180                    Self::optimize(arg);
181                }
182            }
183            JsExpr::NullishCoalescing { left, right, .. } => {
184                Self::optimize(left);
185                Self::optimize(right);
186            }
187            JsExpr::LogicalAssignment { left, right, .. } => {
188                Self::optimize(left);
189                Self::optimize(right);
190            }
191            JsExpr::ArrowFunction { body, .. } => {
192                Self::optimize(body);
193            }
194            JsExpr::TseElement { children, .. } => {
195                for child in children {
196                    Self::optimize(child);
197                }
198            }
199            JsExpr::TemplateLiteral { expressions, .. } => {
200                for expr in expressions {
201                    Self::optimize(expr);
202                }
203            }
204            JsExpr::Spread(expr, ..) => {
205                Self::optimize(expr);
206            }
207            JsExpr::TypeOf(expr, ..) => {
208                Self::optimize(expr);
209            }
210            JsExpr::InstanceOf { left, right, .. } => {
211                Self::optimize(left);
212                Self::optimize(right);
213            }
214            _ => {}
215        }
216    }
217}
218
219/// 语句优化器
220///
221/// 负责优化 JavaScript 语句,包括死代码消除等优化规则。
222pub struct StmtOptimizer;
223
224impl StmtOptimizer {
225    /// 优化语句
226    ///
227    /// # Parameters
228    /// - `stmt`: 要优化的语句
229    pub fn optimize(stmt: &mut JsStmt) {
230        match stmt {
231            JsStmt::Expr(expr, ..) => {
232                ExprOptimizer::optimize(expr);
233            }
234            JsStmt::VariableDecl { init, .. } => {
235                if let Some(expr) = init {
236                    ExprOptimizer::optimize(expr);
237                }
238            }
239            JsStmt::FunctionDecl { body, .. } => {
240                for stmt in body {
241                    Self::optimize(stmt);
242                }
243            }
244            JsStmt::Return(expr, ..) => {
245                if let Some(expr) = expr {
246                    ExprOptimizer::optimize(expr);
247                }
248            }
249            JsStmt::If { test, consequent, alternate, .. } => {
250                ExprOptimizer::optimize(test);
251                Self::optimize(consequent);
252                if let Some(alt) = alternate {
253                    Self::optimize(alt);
254                }
255                // 死代码消除:常量条件
256                if let JsExpr::Literal(test_val, _, _) = test {
257                    if let Some(b) = test_val.as_bool() {
258                        if b {
259                            *stmt = *consequent.clone();
260                        }
261                        else if let Some(alt) = alternate {
262                            *stmt = *alt.clone();
263                        }
264                        else {
265                            *stmt = JsStmt::Block(vec![], Span::unknown(), Trivia::new());
266                        }
267                    }
268                }
269            }
270            JsStmt::While { test, body, .. } => {
271                ExprOptimizer::optimize(test);
272                Self::optimize(body);
273                // 死代码消除:永远为 false 的条件
274                if let JsExpr::Literal(test_val, _, _) = test {
275                    if let Some(b) = test_val.as_bool() {
276                        if !b {
277                            *stmt = JsStmt::Block(vec![], Span::unknown(), Trivia::new());
278                        }
279                    }
280                }
281            }
282            JsStmt::For { init, test, update, body, .. } => {
283                if let Some(init_stmt) = init {
284                    Self::optimize(init_stmt);
285                }
286                if let Some(test_expr) = test {
287                    ExprOptimizer::optimize(test_expr);
288                }
289                if let Some(update_expr) = update {
290                    ExprOptimizer::optimize(update_expr);
291                }
292                Self::optimize(body);
293            }
294            JsStmt::ForIn { left, right, body, .. } => {
295                Self::optimize(left);
296                ExprOptimizer::optimize(right);
297                Self::optimize(body);
298            }
299            JsStmt::ForOf { left, right, body, .. } => {
300                Self::optimize(left);
301                ExprOptimizer::optimize(right);
302                Self::optimize(body);
303            }
304            JsStmt::Try { block, handler, finalizer, .. } => {
305                Self::optimize(block);
306                if let Some((_, body)) = handler {
307                    Self::optimize(body);
308                }
309                if let Some(body) = finalizer {
310                    Self::optimize(body);
311                }
312            }
313            JsStmt::Switch { discriminant, cases, .. } => {
314                ExprOptimizer::optimize(discriminant);
315                for (test, stmts) in cases {
316                    if let Some(test_expr) = test {
317                        ExprOptimizer::optimize(test_expr);
318                    }
319                    for stmt in stmts {
320                        Self::optimize(stmt);
321                    }
322                }
323            }
324            JsStmt::Throw(expr, ..) => {
325                ExprOptimizer::optimize(expr);
326            }
327            JsStmt::Block(stmts, ..) => {
328                // 移除空语句和死代码
329                let mut optimized_stmts = vec![];
330                for stmt in &mut *stmts {
331                    let mut optimized_stmt = stmt.clone();
332                    Self::optimize(&mut optimized_stmt);
333                    // 移除空块
334                    if let JsStmt::Block(inner_stmts, _, _) = optimized_stmt {
335                        if !inner_stmts.is_empty() {
336                            optimized_stmts.extend(inner_stmts);
337                        }
338                    }
339                    else if let JsStmt::Expr(expr, _, _) = &optimized_stmt {
340                        // 移除无效的表达式语句
341                        if !matches!(expr, JsExpr::Identifier(_, _, _)) {
342                            optimized_stmts.push(optimized_stmt);
343                        }
344                    }
345                    else {
346                        optimized_stmts.push(optimized_stmt);
347                    }
348                }
349                *stmts = optimized_stmts;
350            }
351            _ => {}
352        }
353    }
354}
355
356/// 程序优化器
357///
358/// 负责优化 JavaScript 程序,包括移除空语句和死代码等优化规则。
359pub struct ProgramOptimizer;
360
361impl ProgramOptimizer {
362    /// 优化程序
363    ///
364    /// # Parameters
365    /// - `program`: 要优化的程序
366    pub fn optimize(program: &mut JsProgram) {
367        let mut optimized_body = vec![];
368        for stmt in &program.body {
369            let mut optimized_stmt = stmt.clone();
370            StmtOptimizer::optimize(&mut optimized_stmt);
371            // 移除空块
372            if let JsStmt::Block(inner_stmts, _, _) = optimized_stmt {
373                if !inner_stmts.is_empty() {
374                    optimized_body.extend(inner_stmts);
375                }
376            }
377            else {
378                optimized_body.push(optimized_stmt);
379            }
380        }
381        program.body = optimized_body;
382    }
383}
384
385/// IR 模块优化器
386///
387/// 负责优化 IR 模块,包括优化模块中的脚本。
388pub struct IROptimizer;
389
390impl IROptimizer {
391    /// 优化 IR 模块
392    ///
393    /// # Parameters
394    /// - `module`: 要优化的 IR 模块
395    pub fn optimize(module: &mut IRModule) {
396        if let Some(script) = &mut module.script {
397            ProgramOptimizer::optimize(script);
398        }
399        if let Some(script_server) = &mut module.script_server {
400            ProgramOptimizer::optimize(script_server);
401        }
402        if let Some(script_client) = &mut module.script_client {
403            ProgramOptimizer::optimize(script_client);
404        }
405    }
406}