1use crate::ast_structs::{Block, Expression, Program, Property, Statement};
2use crate::parallel;
3use tokio::runtime::Runtime;
4
5const PARALLELISM_THRESHOLD: usize = 2;
6
7pub fn optimize_ast(program: Program, runtime: &Runtime) -> Program {
8
9 let optimized_statements = if program.statements.len() > PARALLELISM_THRESHOLD {
10 parallel::process_items_sync(runtime, program.statements, |stmt, rt| {
11 optimize_statement(stmt, rt)
12 })
13 .into_iter()
14 .filter_map(|s| s)
15 .collect()
16 } else {
17 optimize_statements(program.statements, runtime)
18 };
19
20
21 let optimized = Program::new(optimized_statements, program.location);
22
23 optimized
24}
25
26fn optimize_statements(statements: Vec<Statement>, runtime: &Runtime) -> Vec<Statement> {
27 let mut optimized = Vec::new();
28
29 for statement in statements {
30 match optimize_statement(statement, runtime) {
31 Some(stmt) => optimized.push(stmt),
32 None => {}
33 }
34 }
35
36 optimized
37}
38
39fn optimize_statement(statement: Statement, runtime: &Runtime) -> Option<Statement> {
40 match statement {
41 Statement::Block { block, location } => {
42
43 let optimized_block = optimize_block(block, runtime);
44
45
46 if optimized_block.statements.is_empty() {
47 return None;
48 }
49
50
51
52 if optimized_block.statements.len() == 1 {
53 match &optimized_block.statements[0] {
54 Statement::Block { .. } => {},
55 _ => return Some(optimized_block.statements.into_iter().next().unwrap())
56 }
57 }
58
59 Some(Statement::Block { block: optimized_block, location })
60 },
61 Statement::IfStatement { condition, body, else_body, location } => {
62
63 let optimized_condition = optimize_expression(condition, runtime);
64
65
66 let optimized_body = optimize_block(body, runtime);
67
68
69 let optimized_else_body = else_body.map(|body| optimize_block(body, runtime));
70
71
72 if optimized_body.statements.is_empty() &&
73 optimized_else_body.as_ref().map_or(true, |b| b.statements.is_empty()) {
74 return None;
75 }
76
77 Some(Statement::IfStatement {
78 condition: optimized_condition,
79 body: optimized_body,
80 else_body: optimized_else_body,
81 location
82 })
83 },
84 Statement::ExpressionStatement { expression, location } => {
85 let optimized_expr = optimize_expression(expression, runtime);
86
87 Some(Statement::ExpressionStatement { expression: optimized_expr, location })
88 },
89 Statement::CallbackDeclaration { name, params, body, location } => {
90
91 let optimized_body = optimize_block(body, runtime);
92
93 Some(Statement::CallbackDeclaration {
94 name,
95 params,
96 body: optimized_body,
97 location,
98 })
99 },
100 Statement::ReturnStatement { value, location } => {
101
102 let optimized_value = optimize_expression(value, runtime);
103
104
105 Some(Statement::ReturnStatement { value: optimized_value, location })
106 },
107 Statement::LoopStatement { variable, iterable, body, location } => {
108
109 let optimized_iterable = optimize_expression(iterable, runtime);
110
111
112 let optimized_body = optimize_block(body, runtime);
113
114
115 if optimized_body.statements.is_empty() {
116 return None;
117 }
118
119 Some(Statement::LoopStatement {
120 variable,
121 iterable: optimized_iterable,
122 body: optimized_body,
123 location,
124 })
125 },
126
127 Statement::EndStatement { location } => Some(Statement::EndStatement { location }),
128 Statement::ContinueStatement { location } => Some(Statement::ContinueStatement { location }),
129
130
131 Statement::VariableDeclaration { name, value, location } => {
132 let optimized_value = optimize_expression(value, runtime);
133 Some(Statement::VariableDeclaration { name, value: optimized_value, location })
134 }
135 }
136}
137
138fn optimize_block(block: Block, runtime: &Runtime) -> Block {
139
140 let statements = if block.statements.len() > PARALLELISM_THRESHOLD {
141 parallel::process_items_sync(runtime, block.statements, |stmt, rt| optimize_statement(stmt, rt))
142 .into_iter()
143 .filter_map(|s| s)
144 .collect()
145 } else {
146 optimize_statements(block.statements, runtime)
147 };
148
149
150 let mut flattened = Vec::new();
151 for stmt in statements {
152 match stmt {
153
154 Statement::Block { block: inner_block, .. } => {
155 flattened.extend(inner_block.statements);
156 },
157 _ => flattened.push(stmt)
158 }
159 }
160
161 Block::new(flattened, block.location)
162}
163
164
165fn optimize_expression(expr: Expression, runtime: &Runtime) -> Expression {
166 match expr {
167 Expression::BinaryExpression { left, operator, right, location } => {
168
169 let optimized_left = optimize_expression(*left, runtime);
170 let optimized_right = optimize_expression(*right, runtime);
171 let result = Expression::BinaryExpression {
172 left: Box::new(optimized_left),
173 operator,
174 right: Box::new(optimized_right),
175 location,
176 };
177 result
178 },
179 Expression::AssignmentExpression { target, value, location } => {
180 let optimized_value = Box::new(optimize_expression(*value, runtime));
181 let result = Expression::AssignmentExpression { target, value: optimized_value, location };
182 result
183 },
184 Expression::MemberAssignmentExpression { object, property, property_expr, computed, value, location } => {
185
186 let optimized_object = Box::new(optimize_expression(*object, runtime));
187
188
189 let optimized_prop_expr = match property_expr {
190 Some(expr) => Some(Box::new(optimize_expression(*expr, runtime))),
191 None => None,
192 };
193
194 let optimized_value = Box::new(optimize_expression(*value, runtime));
195 let result = Expression::MemberAssignmentExpression {
196 object: optimized_object,
197 property,
198 property_expr: optimized_prop_expr,
199 computed,
200 value: optimized_value,
201 location,
202 };
203 result
204 },
205 Expression::CallExpression { callee, arguments, location } => {
206
207 let optimized_args = if arguments.len() > PARALLELISM_THRESHOLD {
208 parallel::process_items_sync(runtime, arguments, |arg, rt| optimize_expression(arg, rt))
209 } else {
210 arguments.into_iter().map(|arg| optimize_expression(arg, runtime)).collect()
211 };
212 let result = Expression::CallExpression { callee, arguments: optimized_args, location };
213 result
214 },
215 Expression::ArrayExpression { elements, location } => {
216
217 let optimized_elements = if elements.len() > PARALLELISM_THRESHOLD {
218 parallel::process_items_sync(runtime, elements, |elem, rt| optimize_expression(elem, rt))
219 } else {
220 elements.into_iter().map(|elem| optimize_expression(elem, runtime)).collect()
221 };
222 let result = Expression::ArrayExpression { elements: optimized_elements, location };
223 result
224 },
225 Expression::ObjectExpression { properties, location } => {
226
227 let optimized_properties = if properties.len() > PARALLELISM_THRESHOLD {
228 parallel::process_items_sync(
229 runtime,
230 properties,
231 |prop, rt| Property::new(prop.key, optimize_expression(prop.value, rt), prop.location)
232 )
233 } else {
234 properties.into_iter()
235 .map(|prop| Property::new(prop.key, optimize_expression(prop.value, runtime), prop.location))
236 .collect()
237 };
238 let result = Expression::ObjectExpression { properties: optimized_properties, location };
239 result
240 },
241 Expression::MemberExpression { object, property, property_expr, computed, location } => {
242
243 let optimized_object = Box::new(optimize_expression(*object, runtime));
244
245
246 let optimized_prop_expr = match property_expr {
247 Some(expr) => Some(Box::new(optimize_expression(*expr, runtime))),
248 None => None,
249 };
250 let result = Expression::MemberExpression {
251 object: optimized_object,
252 property,
253 property_expr: optimized_prop_expr,
254 computed,
255 location,
256 };
257 result
258 },
259 Expression::KeysOfExpression { object, location } => {
260 let optimized_object = Box::new(optimize_expression(*object, runtime));
261 let result = Expression::KeysOfExpression { object: optimized_object, location };
262 result
263 },
264 Expression::MemberCallExpression { object, property, property_expr, computed, arguments, location } => {
265
266 let optimized_object = Box::new(optimize_expression(*object, runtime));
267
268
269 let optimized_prop_expr = match property_expr {
270 Some(expr) => Some(Box::new(optimize_expression(*expr, runtime))),
271 None => None,
272 };
273
274
275 let optimized_args = if arguments.len() > PARALLELISM_THRESHOLD {
276 parallel::process_items_sync(runtime, arguments, |arg, rt| optimize_expression(arg, rt))
277 } else {
278 arguments.into_iter().map(|arg| optimize_expression(arg, runtime)).collect()
279 };
280
281 Expression::MemberCallExpression {
282 object: optimized_object,
283 property,
284 property_expr: optimized_prop_expr,
285 computed,
286 arguments: optimized_args,
287 location,
288 }
289 },
290 Expression::InlineCallbackExpression { name, params, body, location } => {
291 let optimized_body = optimize_block(body, runtime);
292
293 Expression::InlineCallbackExpression {
294 name,
295 params,
296 body: optimized_body,
297 location,
298 }
299 },
300 Expression::UnaryExpression { operator, operand, location } => {
301 let optimized_operand = Box::new(optimize_expression(*operand, runtime));
302 Expression::UnaryExpression {
303 operator,
304 operand: optimized_operand,
305 location,
306 }
307 },
308 Expression::StringLiteral { .. } |
309 Expression::NumberLiteral { .. } |
310 Expression::Identifier { .. } |
311 Expression::BooleanLiteral { .. } |
312 Expression::NullLiteral { .. } => {
313 expr
314 },
315 }
316}