From ea466afdc8dc6b64be81244a8c0261ac34f22157 Mon Sep 17 00:00:00 2001 From: Pig Fang Date: Fri, 15 Apr 2022 22:16:31 +0800 Subject: [PATCH] fix(es/parser): Make parsing of TS InstantiationExpr more permissive (#4332) --- crates/swc_ecma_parser/src/macros.rs | 2 +- crates/swc_ecma_parser/src/parser/expr.rs | 17 +++ crates/swc_ecma_parser/src/parser/macros.rs | 7 ++ .../swc_ecma_parser/src/parser/typescript.rs | 11 +- .../instantiation-expr/asi/input.ts | 4 + .../instantiation-expr/asi/input.ts.json | 106 +++++++++++++++++- 6 files changed, 137 insertions(+), 10 deletions(-) diff --git a/crates/swc_ecma_parser/src/macros.rs b/crates/swc_ecma_parser/src/macros.rs index 0f20a3afbc6..a0b1646eb4b 100644 --- a/crates/swc_ecma_parser/src/macros.rs +++ b/crates/swc_ecma_parser/src/macros.rs @@ -101,7 +101,7 @@ macro_rules! tok { crate::token::Token::BinOp(crate::token::BinOpToken::Div) }; ("/=") => { - crate::token::Token::AssignOp(DivAssign) + crate::token::Token::AssignOp(crate::token::AssignOpToken::DivAssign) }; ('%') => { crate::token::Token::BinOp(Mod) diff --git a/crates/swc_ecma_parser/src/parser/expr.rs b/crates/swc_ecma_parser/src/parser/expr.rs index ed84f099929..426270e27ea 100644 --- a/crates/swc_ecma_parser/src/parser/expr.rs +++ b/crates/swc_ecma_parser/src/parser/expr.rs @@ -1903,4 +1903,21 @@ impl<'a, I: Tokens> Parser { } } } + + fn is_start_of_left_hand_side_expr(&mut self) -> PResult { + Ok(is_one_of!( + self, "this", "super", "null", "true", "false", Num, BigInt, Str, '`', '(', '[', '{', + "function", "class", "new", Regex, IdentRef + ) || (is!(self, "import") + && (peeked_is!(self, '(') || peeked_is!(self, '<') || peeked_is!(self, '.')))) + } + + pub(super) fn is_start_of_expr(&mut self) -> PResult { + Ok(self.is_start_of_left_hand_side_expr()? + || is_one_of!( + self, '+', '-', '~', '!', "delete", "typeof", "void", "++", "--", '<', "await", + "yield" + ) + || (is!(self, '#') && peeked_is!(self, IdentName))) + } } diff --git a/crates/swc_ecma_parser/src/parser/macros.rs b/crates/swc_ecma_parser/src/parser/macros.rs index 5a8b523c440..2dcc5586b3e 100644 --- a/crates/swc_ecma_parser/src/parser/macros.rs +++ b/crates/swc_ecma_parser/src/parser/macros.rs @@ -53,6 +53,13 @@ macro_rules! is { } }}; + ($p:expr,Regex) => {{ + match cur!($p, false) { + Ok(&Token::Regex { .. }) => true, + _ => false, + } + }}; + ($p:expr,BigInt) => {{ match cur!($p, false) { Ok(&Token::BigInt { .. }) => true, diff --git a/crates/swc_ecma_parser/src/parser/typescript.rs b/crates/swc_ecma_parser/src/parser/typescript.rs index d7cd6383a15..ec26a6a5453 100644 --- a/crates/swc_ecma_parser/src/parser/typescript.rs +++ b/crates/swc_ecma_parser/src/parser/typescript.rs @@ -565,15 +565,10 @@ impl Parser { self.try_parse_ts(|p| { let type_args = p.parse_ts_type_args()?; - if is_one_of!( - p, ',', '.', '?', ')', ']', ':', '&', '|', '^', '}', "??", "==", "===", "!=", - "!==", "&&", "||" - ) || is_exact!(p, ';') - || eof!(p) - { - Ok(Some(type_args)) - } else { + if p.is_start_of_expr()? { Ok(None) + } else { + Ok(Some(type_args)) } }) } diff --git a/crates/swc_ecma_parser/tests/typescript/instantiation-expr/asi/input.ts b/crates/swc_ecma_parser/tests/typescript/instantiation-expr/asi/input.ts index 66d0e3b1d82..1cea4ef37a3 100644 --- a/crates/swc_ecma_parser/tests/typescript/instantiation-expr/asi/input.ts +++ b/crates/swc_ecma_parser/tests/typescript/instantiation-expr/asi/input.ts @@ -9,3 +9,7 @@ true; // Parsed as instantiation expression const x3 = f; true; + +// Parsed as instantiation expression +const x4 = f +if (true) {} diff --git a/crates/swc_ecma_parser/tests/typescript/instantiation-expr/asi/input.ts.json b/crates/swc_ecma_parser/tests/typescript/instantiation-expr/asi/input.ts.json index b96c2868ead..b94f935cb8e 100644 --- a/crates/swc_ecma_parser/tests/typescript/instantiation-expr/asi/input.ts.json +++ b/crates/swc_ecma_parser/tests/typescript/instantiation-expr/asi/input.ts.json @@ -2,7 +2,7 @@ "type": "Script", "span": { "start": 69, - "end": 221, + "end": 292, "ctxt": 0 }, "body": [ @@ -268,6 +268,110 @@ }, "value": true } + }, + { + "type": "VariableDeclaration", + "span": { + "start": 261, + "end": 279, + "ctxt": 0 + }, + "kind": "const", + "declare": false, + "declarations": [ + { + "type": "VariableDeclarator", + "span": { + "start": 267, + "end": 279, + "ctxt": 0 + }, + "id": { + "type": "Identifier", + "span": { + "start": 267, + "end": 269, + "ctxt": 0 + }, + "value": "x4", + "optional": false, + "typeAnnotation": null + }, + "init": { + "type": "TsInstantiation", + "span": { + "start": 272, + "end": 279, + "ctxt": 0 + }, + "expression": { + "type": "Identifier", + "span": { + "start": 272, + "end": 273, + "ctxt": 0 + }, + "value": "f", + "optional": false + }, + "typeArguments": { + "type": "TsTypeParameterInstantiation", + "span": { + "start": 273, + "end": 279, + "ctxt": 0 + }, + "params": [ + { + "type": "TsLiteralType", + "span": { + "start": 274, + "end": 278, + "ctxt": 0 + }, + "literal": { + "type": "BooleanLiteral", + "span": { + "start": 274, + "end": 278, + "ctxt": 0 + }, + "value": true + } + } + ] + } + }, + "definite": false + } + ] + }, + { + "type": "IfStatement", + "span": { + "start": 280, + "end": 292, + "ctxt": 0 + }, + "test": { + "type": "BooleanLiteral", + "span": { + "start": 284, + "end": 288, + "ctxt": 0 + }, + "value": true + }, + "consequent": { + "type": "BlockStatement", + "span": { + "start": 290, + "end": 292, + "ctxt": 0 + }, + "stmts": [] + }, + "alternate": null } ], "interpreter": null