@samitouri / QOS-React-2 / commits / 2b168ad673

[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(&param.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 +}