[rust] SWC->ESTree conversion
Start of converting swc's representation into our estree format.
Joe Savona committed
Jul 6, 2023 at 09:24 UTC
2b168ad673f35854a16b1b5df5ccd916331aa8d1
2 files changed
+390
compiler/forget/crates/estree-swc/Cargo.toml
new
+11
@@ -0,0 +1,11 @@
1
+[package]
2
+name = "estree-swc"
3
+version = "0.1.0"
4
+edition = "2021"
5
+
6
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7
+
8
+[dependencies]
9
+swc_ecma_ast = { version = "0.106.6", features = ["serde", "serde-impl"] }
10
+estree = { path = "../estree" }
11
+swc_common = "0.31.16"
compiler/forget/crates/estree-swc/src/lib.rs
new
+379
@@ -0,0 +1,379 @@
1
+use std::num::NonZeroU32;
2
+
3
+use swc_common::{source_map::Pos, Span};
4
+use swc_ecma_ast::{
5
+ AssignOp, BinaryOp, BlockStmt, Decl, Expr, Ident, Lit, ModuleItem, Pat, PatOrExpr, Program,
6
+ Stmt, UnaryOp, VarDeclKind, VarDeclOrExpr,
7
+};
8
+
9
+pub fn convert_program(program: &Program) -> estree::Program {
10
+ let mut program_items: Vec<estree::ModuleItem>;
11
+ match program {
12
+ Program::Module(program) => {
13
+ let body = &program.body;
14
+ program_items = Vec::with_capacity(body.len());
15
+ for item in body {
16
+ program_items.push(convert_module_item(item));
17
+ }
18
+ }
19
+ Program::Script(program) => {
20
+ let body = &program.body;
21
+ program_items = Vec::with_capacity(body.len());
22
+ for item in body {
23
+ program_items.push(estree::ModuleItem::Statement(Box::new(convert_statement(
24
+ item,
25
+ ))));
26
+ }
27
+ }
28
+ };
29
+ estree::Program {
30
+ source_type: if program.is_script() {
31
+ estree::SourceType::Script
32
+ } else {
33
+ estree::SourceType::Module
34
+ },
35
+ body: program_items,
36
+ comments: None,
37
+ loc: None,
38
+ range: None,
39
+ }
40
+}
41
+
42
+fn convert_module_item(item: &ModuleItem) -> estree::ModuleItem {
43
+ match item {
44
+ ModuleItem::Stmt(item) => estree::ModuleItem::Statement(Box::new(convert_statement(item))),
45
+ _ => todo!(),
46
+ }
47
+}
48
+
49
+fn convert_span(span: &Span) -> Option<estree::SourceRange> {
50
+ Some(estree::SourceRange {
51
+ start: span.lo().to_u32(),
52
+ end: NonZeroU32::new(span.hi().to_u32())?,
53
+ })
54
+}
55
+
56
+fn convert_decl_kind(kind: &VarDeclKind) -> estree::VariableDeclarationKind {
57
+ match kind {
58
+ VarDeclKind::Const => estree::VariableDeclarationKind::Const,
59
+ VarDeclKind::Let => estree::VariableDeclarationKind::Let,
60
+ VarDeclKind::Var => estree::VariableDeclarationKind::Var,
61
+ }
62
+}
63
+
64
+fn convert_block_statement(stmt: &BlockStmt) -> estree::BlockStatement {
65
+ let mut body: Vec<estree::Statement> = Vec::with_capacity(stmt.stmts.len());
66
+ for stmt in &stmt.stmts {
67
+ body.push(convert_statement(stmt));
68
+ }
69
+ estree::BlockStatement {
70
+ body,
71
+ loc: None,
72
+ range: convert_span(&stmt.span),
73
+ }
74
+}
75
+
76
+fn convert_statement(stmt: &Stmt) -> estree::Statement {
77
+ match stmt {
78
+ Stmt::Decl(Decl::Fn(item)) => {
79
+ let name = item.ident.sym.to_string();
80
+ estree::Statement::FunctionDeclaration(Box::new(estree::FunctionDeclaration {
81
+ id: Some(estree::Identifier {
82
+ name,
83
+ loc: None,
84
+ range: convert_span(&item.ident.span),
85
+ }),
86
+ params: item
87
+ .function
88
+ .params
89
+ .iter()
90
+ .map(|param| convert_pattern(¶m.pat))
91
+ .collect(),
92
+ body: item.function.body.as_ref().map(|body| {
93
+ estree::Statement::BlockStatement(Box::new(convert_block_statement(body)))
94
+ }),
95
+ is_async: item.function.is_async,
96
+ is_generator: item.function.is_generator,
97
+ loc: None,
98
+ range: convert_span(&item.function.span),
99
+ }))
100
+ }
101
+ Stmt::Block(item) => {
102
+ estree::Statement::BlockStatement(Box::new(convert_block_statement(item)))
103
+ }
104
+ Stmt::Break(item) => estree::Statement::BreakStatement(Box::new(estree::BreakStatement {
105
+ label: item.label.as_ref().map(|label| convert_identifier(label)),
106
+ loc: None,
107
+ range: convert_span(&item.span),
108
+ })),
109
+ Stmt::Continue(item) => {
110
+ estree::Statement::ContinueStatement(Box::new(estree::ContinueStatement {
111
+ label: item.label.as_ref().map(|label| convert_identifier(label)),
112
+ loc: None,
113
+ range: convert_span(&item.span),
114
+ }))
115
+ }
116
+ Stmt::Debugger(item) => {
117
+ estree::Statement::DebuggerStatement(Box::new(estree::DebuggerStatement {
118
+ loc: None,
119
+ range: convert_span(&item.span),
120
+ }))
121
+ }
122
+ Stmt::DoWhile(item) => {
123
+ estree::Statement::DoWhileStatement(Box::new(estree::DoWhileStatement {
124
+ body: convert_statement(&item.body),
125
+ test: convert_expression(&item.test),
126
+ loc: None,
127
+ range: convert_span(&item.span),
128
+ }))
129
+ }
130
+ Stmt::Empty(item) => estree::Statement::EmptyStatement(Box::new(estree::EmptyStatement {
131
+ loc: None,
132
+ range: convert_span(&item.span),
133
+ })),
134
+ Stmt::Expr(item) => {
135
+ let expression = convert_expression(&item.expr);
136
+ estree::Statement::ExpressionStatement(Box::new(estree::ExpressionStatement {
137
+ expression,
138
+ directive: None,
139
+ loc: None,
140
+ range: convert_span(&item.span),
141
+ }))
142
+ }
143
+ Stmt::For(item) => estree::Statement::ForStatement(Box::new(estree::ForStatement {
144
+ init: item.init.as_ref().map(|init| match init {
145
+ VarDeclOrExpr::Expr(init) => {
146
+ estree::ForInit::Expression(Box::new(convert_expression(init)))
147
+ }
148
+ VarDeclOrExpr::VarDecl(init) => {
149
+ assert_eq!(init.decls.len(), 1);
150
+ let decl = &init.decls[0];
151
+ estree::ForInit::VariableDeclaration(Box::new(estree::VariableDeclaration {
152
+ kind: convert_decl_kind(&init.kind),
153
+ declarations: vec![estree::VariableDeclarator {
154
+ id: convert_pattern(&decl.name),
155
+ init: decl.init.as_ref().map(|init| convert_expression(init)),
156
+ loc: None,
157
+ range: convert_span(&decl.span),
158
+ }],
159
+ loc: None,
160
+ range: convert_span(&init.span),
161
+ }))
162
+ }
163
+ }),
164
+ test: item.test.as_ref().map(|test| convert_expression(test)),
165
+ update: item
166
+ .update
167
+ .as_ref()
168
+ .map(|update| convert_expression(update)),
169
+ body: convert_statement(&item.body),
170
+ loc: None,
171
+ range: convert_span(&item.span),
172
+ })),
173
+ Stmt::Return(item) => {
174
+ estree::Statement::ReturnStatement(Box::new(estree::ReturnStatement {
175
+ argument: item.arg.as_ref().map(|arg| convert_expression(arg)),
176
+ loc: None,
177
+ range: convert_span(&item.span),
178
+ }))
179
+ }
180
+ Stmt::Throw(item) => estree::Statement::ThrowStatement(Box::new(estree::ThrowStatement {
181
+ argument: convert_expression(&item.arg),
182
+ loc: None,
183
+ range: convert_span(&item.span),
184
+ })),
185
+ Stmt::If(item) => estree::Statement::IfStatement(Box::new(estree::IfStatement {
186
+ test: convert_expression(&item.test),
187
+ consequent: convert_statement(&item.cons),
188
+ alternate: item.alt.as_ref().map(|alt| convert_statement(alt)),
189
+ loc: None,
190
+ range: convert_span(&item.span),
191
+ })),
192
+ _ => todo!(),
193
+ }
194
+}
195
+
196
+fn convert_expression(expr: &Expr) -> estree::ExpressionLike {
197
+ match expr {
198
+ Expr::Ident(expr) => estree::ExpressionLike::Identifier(Box::new(convert_identifier(expr))),
199
+ Expr::Array(expr) => {
200
+ estree::ExpressionLike::ArrayExpression(Box::new(estree::ArrayExpression {
201
+ elements: expr
202
+ .elems
203
+ .iter()
204
+ .map(|item| {
205
+ // TODO: represent holes in array expressions
206
+ let value = item.as_ref().unwrap();
207
+ match value.spread {
208
+ Some(spread) => estree::ExpressionLike::SpreadElement(Box::new(
209
+ estree::SpreadElement {
210
+ argument: convert_expression(&value.expr),
211
+ loc: None,
212
+ range: convert_span(&spread),
213
+ },
214
+ )),
215
+ None => convert_expression(&value.expr),
216
+ }
217
+ })
218
+ .collect(),
219
+ loc: None,
220
+ range: convert_span(&expr.span),
221
+ }))
222
+ }
223
+ Expr::Await(expr) => {
224
+ estree::ExpressionLike::AwaitExpression(Box::new(estree::AwaitExpression {
225
+ argument: convert_expression(&expr.arg),
226
+ loc: None,
227
+ range: convert_span(&expr.span),
228
+ }))
229
+ }
230
+ Expr::Unary(expr) => {
231
+ estree::ExpressionLike::UnaryExpression(Box::new(estree::UnaryExpression {
232
+ operator: convert_unary_operator(expr.op),
233
+ is_prefix: false,
234
+ argument: convert_expression(&expr.arg),
235
+ loc: None,
236
+ range: convert_span(&expr.span),
237
+ }))
238
+ }
239
+ Expr::Bin(expr) => match convert_binary_operator(expr.op) {
240
+ Operator::Binary(op) => {
241
+ estree::ExpressionLike::BinaryExpression(Box::new(estree::BinaryExpression {
242
+ operator: op,
243
+ left: convert_expression(&expr.left),
244
+ right: convert_expression(&expr.right),
245
+ loc: None,
246
+ range: convert_span(&expr.span),
247
+ }))
248
+ }
249
+ Operator::Logical(op) => {
250
+ estree::ExpressionLike::LogicalExpression(Box::new(estree::LogicalExpression {
251
+ operator: op,
252
+ left: convert_expression(&expr.left),
253
+ right: convert_expression(&expr.right),
254
+ loc: None,
255
+ range: convert_span(&expr.span),
256
+ }))
257
+ }
258
+ },
259
+ Expr::Lit(expr) => {
260
+ let (value, range) = match expr {
261
+ Lit::Bool(expr) => (
262
+ estree::LiteralValue::Boolean(expr.value),
263
+ convert_span(&expr.span),
264
+ ),
265
+ Lit::Num(expr) => (
266
+ estree::LiteralValue::Number(expr.value.into()),
267
+ convert_span(&expr.span),
268
+ ),
269
+ Lit::Str(expr) => (
270
+ estree::LiteralValue::String(expr.value.to_string()),
271
+ convert_span(&expr.span),
272
+ ),
273
+ Lit::Null(expr) => (estree::LiteralValue::Null, convert_span(&expr.span)),
274
+ _ => todo!(),
275
+ };
276
+ estree::ExpressionLike::Literal(Box::new(estree::Literal {
277
+ value,
278
+ raw: None,
279
+ loc: None,
280
+ range,
281
+ }))
282
+ }
283
+ Expr::Assign(expr) => {
284
+ estree::ExpressionLike::AssignmentExpression(Box::new(estree::AssignmentExpression {
285
+ operator: convert_assignment_operator(expr.op),
286
+ left: convert_assignment_target(&expr.left),
287
+ right: convert_expression(&expr.right),
288
+ loc: None,
289
+ range: convert_span(&expr.span),
290
+ }))
291
+ }
292
+ _ => todo!(),
293
+ }
294
+}
295
+
296
+fn convert_assignment_target(_target: &PatOrExpr) -> estree::AssignmentTarget {
297
+ todo!()
298
+}
299
+
300
+fn convert_unary_operator(op: UnaryOp) -> estree::UnaryOperator {
301
+ match op {
302
+ UnaryOp::Bang => estree::UnaryOperator::Exclamation,
303
+ UnaryOp::Delete => estree::UnaryOperator::Delete,
304
+ UnaryOp::Minus => estree::UnaryOperator::Minus,
305
+ UnaryOp::Plus => estree::UnaryOperator::Plus,
306
+ UnaryOp::Tilde => estree::UnaryOperator::Tilde,
307
+ UnaryOp::TypeOf => estree::UnaryOperator::Typeof,
308
+ UnaryOp::Void => estree::UnaryOperator::Void,
309
+ }
310
+}
311
+
312
+fn convert_assignment_operator(op: AssignOp) -> estree::AssignmentOperator {
313
+ match op {
314
+ AssignOp::AddAssign => estree::AssignmentOperator::PlusEquals,
315
+ _ => todo!(),
316
+ }
317
+}
318
+
319
+enum Operator {
320
+ Binary(estree::BinaryOperator),
321
+ Logical(estree::LogicalOperator),
322
+}
323
+
324
+fn convert_binary_operator(op: BinaryOp) -> Operator {
325
+ match op {
326
+ BinaryOp::Add => Operator::Binary(estree::BinaryOperator::Plus),
327
+ BinaryOp::BitAnd => Operator::Binary(estree::BinaryOperator::Ampersand),
328
+ BinaryOp::BitOr => Operator::Binary(estree::BinaryOperator::Pipe),
329
+ BinaryOp::BitXor => Operator::Binary(estree::BinaryOperator::Caret),
330
+ BinaryOp::Div => Operator::Binary(estree::BinaryOperator::Slash),
331
+ BinaryOp::EqEq => Operator::Binary(estree::BinaryOperator::EqualsEquals),
332
+ BinaryOp::EqEqEq => Operator::Binary(estree::BinaryOperator::TripleEquals),
333
+ BinaryOp::Exp => Operator::Binary(estree::BinaryOperator::AsteriskAsterisk),
334
+ BinaryOp::Gt => Operator::Binary(estree::BinaryOperator::GreaterThan),
335
+ BinaryOp::GtEq => Operator::Binary(estree::BinaryOperator::GreaterThanEquals),
336
+ BinaryOp::In => Operator::Binary(estree::BinaryOperator::In),
337
+ BinaryOp::InstanceOf => Operator::Binary(estree::BinaryOperator::Instanceof),
338
+ BinaryOp::LShift => Operator::Binary(estree::BinaryOperator::LtLt),
339
+ BinaryOp::Lt => Operator::Binary(estree::BinaryOperator::LessThan),
340
+ BinaryOp::LtEq => Operator::Binary(estree::BinaryOperator::LessThanEquals),
341
+ BinaryOp::Mod => Operator::Binary(estree::BinaryOperator::Percent),
342
+ BinaryOp::Mul => Operator::Binary(estree::BinaryOperator::Asterisk),
343
+ BinaryOp::NotEq => Operator::Binary(estree::BinaryOperator::NotEquals),
344
+ BinaryOp::NotEqEq => Operator::Binary(estree::BinaryOperator::NotTripleEquals),
345
+ BinaryOp::RShift => Operator::Binary(estree::BinaryOperator::GtGt),
346
+ BinaryOp::Sub => Operator::Binary(estree::BinaryOperator::Minus),
347
+ BinaryOp::ZeroFillRShift => Operator::Binary(estree::BinaryOperator::GtGtGt),
348
+
349
+ BinaryOp::LogicalAnd => Operator::Logical(estree::LogicalOperator::AmpersandAmpersand),
350
+ BinaryOp::LogicalOr => Operator::Logical(estree::LogicalOperator::PipePipe),
351
+ BinaryOp::NullishCoalescing => Operator::Logical(estree::LogicalOperator::QuestionQuestion),
352
+ }
353
+}
354
+
355
+fn convert_pattern(pat: &Pat) -> estree::Pattern {
356
+ match pat {
357
+ Pat::Ident(pat) => estree::Pattern::Identifier(Box::new(estree::Identifier {
358
+ name: pat.id.sym.to_string(),
359
+ loc: None,
360
+ range: convert_span(&pat.span),
361
+ })),
362
+ _ => todo!(),
363
+ }
364
+}
365
+
366
+fn convert_identifier(identifier: &Ident) -> estree::Identifier {
367
+ let name = identifier.sym.as_ref().to_string();
368
+ estree::Identifier {
369
+ name,
370
+ loc: None,
371
+ range: convert_span(&identifier.span),
372
+ }
373
+}
374
+
375
+#[cfg(test)]
376
+mod tests {
377
+ #[test]
378
+ fn it_works() {}
379
+}