From cbc823031042638c99fd58692ac94527d1ab1852 Mon Sep 17 00:00:00 2001 From: Sosuke Suzuki Date: Fri, 3 Sep 2021 14:57:23 +0900 Subject: [PATCH] fix(es/parser): Fix parsing of static blocks (#2200) swc_ecma_parser: - Fix parsing of static blocks with line breaks. (#2195) --- Cargo.lock | 2 +- ecmascript/parser/Cargo.toml | 2 +- ecmascript/parser/src/parser/class_and_fn.rs | 41 +++-- ecmascript/parser/src/parser/stmt.rs | 108 +++++++++++++ .../js/decl/static-blocks-with-line-breaks.js | 6 + .../static-blocks-with-line-breaks.js.spans | 149 ++++++++++++++++++ .../tests/span/js/decl/static-blocks.js | 5 + .../tests/span/js/decl/static-blocks.js.spans | 143 +++++++++++++++++ 8 files changed, 437 insertions(+), 19 deletions(-) create mode 100644 ecmascript/parser/tests/span/js/decl/static-blocks-with-line-breaks.js create mode 100644 ecmascript/parser/tests/span/js/decl/static-blocks-with-line-breaks.js.spans create mode 100644 ecmascript/parser/tests/span/js/decl/static-blocks.js create mode 100644 ecmascript/parser/tests/span/js/decl/static-blocks.js.spans diff --git a/Cargo.lock b/Cargo.lock index 389d3298ead..d6378600d21 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2661,7 +2661,7 @@ dependencies = [ [[package]] name = "swc_ecma_parser" -version = "0.70.0" +version = "0.70.1" dependencies = [ "either", "enum_kind", diff --git a/ecmascript/parser/Cargo.toml b/ecmascript/parser/Cargo.toml index 5dac363bdcd..131a998e57c 100644 --- a/ecmascript/parser/Cargo.toml +++ b/ecmascript/parser/Cargo.toml @@ -7,7 +7,7 @@ include = ["Cargo.toml", "src/**/*.rs", "examples/**/*.rs"] license = "Apache-2.0/MIT" name = "swc_ecma_parser" repository = "https://github.com/swc-project/swc.git" -version = "0.70.0" +version = "0.70.1" [package.metadata.docs.rs] all-features = true diff --git a/ecmascript/parser/src/parser/class_and_fn.rs b/ecmascript/parser/src/parser/class_and_fn.rs index b90020aa1e5..d4a032c2793 100644 --- a/ecmascript/parser/src/parser/class_and_fn.rs +++ b/ecmascript/parser/src/parser/class_and_fn.rs @@ -404,23 +404,30 @@ impl<'a, I: Tokens> Parser { } else if self.is_class_property()? { // Property named `static` - let key = Either::Right(PropName::Ident(Ident::new( - js_word!("static"), - static_token, - ))); - let is_optional = self.input.syntax().typescript() && eat!(self, '?'); - return self.make_property( - start, - decorators, - accessibility, - key, - false, - is_optional, - false, - declare, - false, - false, - ); + // Avoid to parse + // static + // {} + let is_parsing_static_blocks = + self.input.syntax().static_blocks() && is!(self, '{'); + if !is_parsing_static_blocks { + let key = Either::Right(PropName::Ident(Ident::new( + js_word!("static"), + static_token, + ))); + let is_optional = self.input.syntax().typescript() && eat!(self, '?'); + return self.make_property( + start, + decorators, + accessibility, + key, + false, + is_optional, + false, + declare, + false, + false, + ); + } } else { // TODO: error if static contains escape } diff --git a/ecmascript/parser/src/parser/stmt.rs b/ecmascript/parser/src/parser/stmt.rs index 965388c6734..95dd0d56fc1 100644 --- a/ecmascript/parser/src/parser/stmt.rs +++ b/ecmascript/parser/src/parser/stmt.rs @@ -1976,6 +1976,90 @@ export default function waitUntil(callback, options = {}) { ); } + #[test] + fn class_static_blocks_with_line_breaks_01() { + let src = "class Foo { + static + { + 1 + 1; + } + }"; + assert_eq_ignore_span!( + test_parser( + src, + Syntax::Es(EsConfig { + static_blocks: true, + ..Default::default() + }), + |p| p.parse_expr() + ), + Box::new(Expr::Class(ClassExpr { + ident: Some(Ident { + span, + sym: "Foo".into(), + optional: false, + }), + class: Class { + span, + decorators: Vec::new(), + super_class: None, + type_params: None, + super_type_params: None, + is_abstract: false, + implements: Vec::new(), + body: vec!(ClassMember::StaticBlock(StaticBlock { + span, + body: BlockStmt { + span, + stmts: vec!(stmt("1 + 1;")), + } + })) + } + })) + ); + } + + #[test] + fn class_static_blocks_with_line_breaks_02() { + let src = "class Foo { + static + {} + }"; + assert_eq_ignore_span!( + test_parser( + src, + Syntax::Es(EsConfig { + static_blocks: true, + ..Default::default() + }), + |p| p.parse_expr() + ), + Box::new(Expr::Class(ClassExpr { + ident: Some(Ident { + span, + sym: "Foo".into(), + optional: false, + }), + class: Class { + span, + decorators: Vec::new(), + super_class: None, + type_params: None, + super_type_params: None, + is_abstract: false, + implements: Vec::new(), + body: vec!(ClassMember::StaticBlock(StaticBlock { + span, + body: BlockStmt { + span, + stmts: Vec::new(), + } + })) + } + })) + ); + } + #[test] fn class_static_blocks_in_ts() { let src = "class Foo { static { 1 + 1 }; }"; @@ -1984,6 +2068,30 @@ export default function waitUntil(callback, options = {}) { }); } + #[test] + fn class_static_blocks_with_line_breaks_in_ts_01() { + let src = "class Foo { + static + { + 1 + 1; + } + }"; + test_parser(src, Syntax::Typescript(Default::default()), |p| { + p.parse_expr() + }); + } + + #[test] + fn class_static_blocks_with_line_breaks_in_ts_02() { + let src = "class Foo { + static + {} + }"; + test_parser(src, Syntax::Typescript(Default::default()), |p| { + p.parse_expr() + }); + } + #[test] #[should_panic(expected = "Modifiers cannot appear here")] fn class_static_blocks_in_ts_with_invalid_modifier_01() { diff --git a/ecmascript/parser/tests/span/js/decl/static-blocks-with-line-breaks.js b/ecmascript/parser/tests/span/js/decl/static-blocks-with-line-breaks.js new file mode 100644 index 00000000000..e58aaf1190e --- /dev/null +++ b/ecmascript/parser/tests/span/js/decl/static-blocks-with-line-breaks.js @@ -0,0 +1,6 @@ +class Foo { + static + { + 1 + 1; + } +} diff --git a/ecmascript/parser/tests/span/js/decl/static-blocks-with-line-breaks.js.spans b/ecmascript/parser/tests/span/js/decl/static-blocks-with-line-breaks.js.spans new file mode 100644 index 00000000000..b21f13eede8 --- /dev/null +++ b/ecmascript/parser/tests/span/js/decl/static-blocks-with-line-breaks.js.spans @@ -0,0 +1,149 @@ +warning: Module + --> $DIR/tests/span/js/decl/static-blocks-with-line-breaks.js:1:1 + | +1 | / class Foo { +2 | | static +3 | | { +4 | | 1 + 1; +5 | | } +6 | | } + | |_^ + +warning: ModuleItem + --> $DIR/tests/span/js/decl/static-blocks-with-line-breaks.js:1:1 + | +1 | / class Foo { +2 | | static +3 | | { +4 | | 1 + 1; +5 | | } +6 | | } + | |_^ + +warning: Stmt + --> $DIR/tests/span/js/decl/static-blocks-with-line-breaks.js:1:1 + | +1 | / class Foo { +2 | | static +3 | | { +4 | | 1 + 1; +5 | | } +6 | | } + | |_^ + +warning: Decl + --> $DIR/tests/span/js/decl/static-blocks-with-line-breaks.js:1:1 + | +1 | / class Foo { +2 | | static +3 | | { +4 | | 1 + 1; +5 | | } +6 | | } + | |_^ + +warning: ClassDecl + --> $DIR/tests/span/js/decl/static-blocks-with-line-breaks.js:1:1 + | +1 | / class Foo { +2 | | static +3 | | { +4 | | 1 + 1; +5 | | } +6 | | } + | |_^ + +warning: Ident + --> $DIR/tests/span/js/decl/static-blocks-with-line-breaks.js:1:7 + | +1 | class Foo { + | ^^^ + +warning: Class + --> $DIR/tests/span/js/decl/static-blocks-with-line-breaks.js:1:1 + | +1 | / class Foo { +2 | | static +3 | | { +4 | | 1 + 1; +5 | | } +6 | | } + | |_^ + +warning: ClassMember + --> $DIR/tests/span/js/decl/static-blocks-with-line-breaks.js:2:5 + | +2 | / static +3 | | { +4 | | 1 + 1; +5 | | } + | |_____^ + +warning: BlockStmt + --> $DIR/tests/span/js/decl/static-blocks-with-line-breaks.js:3:5 + | +3 | / { +4 | | 1 + 1; +5 | | } + | |_____^ + +warning: Stmt + --> $DIR/tests/span/js/decl/static-blocks-with-line-breaks.js:4:9 + | +4 | 1 + 1; + | ^^^^^^ + +warning: ExprStmt + --> $DIR/tests/span/js/decl/static-blocks-with-line-breaks.js:4:9 + | +4 | 1 + 1; + | ^^^^^^ + +warning: Expr + --> $DIR/tests/span/js/decl/static-blocks-with-line-breaks.js:4:9 + | +4 | 1 + 1; + | ^^^^^ + +warning: BinExpr + --> $DIR/tests/span/js/decl/static-blocks-with-line-breaks.js:4:9 + | +4 | 1 + 1; + | ^^^^^ + +warning: Expr + --> $DIR/tests/span/js/decl/static-blocks-with-line-breaks.js:4:9 + | +4 | 1 + 1; + | ^ + +warning: Lit + --> $DIR/tests/span/js/decl/static-blocks-with-line-breaks.js:4:9 + | +4 | 1 + 1; + | ^ + +warning: Number + --> $DIR/tests/span/js/decl/static-blocks-with-line-breaks.js:4:9 + | +4 | 1 + 1; + | ^ + +warning: Expr + --> $DIR/tests/span/js/decl/static-blocks-with-line-breaks.js:4:13 + | +4 | 1 + 1; + | ^ + +warning: Lit + --> $DIR/tests/span/js/decl/static-blocks-with-line-breaks.js:4:13 + | +4 | 1 + 1; + | ^ + +warning: Number + --> $DIR/tests/span/js/decl/static-blocks-with-line-breaks.js:4:13 + | +4 | 1 + 1; + | ^ + diff --git a/ecmascript/parser/tests/span/js/decl/static-blocks.js b/ecmascript/parser/tests/span/js/decl/static-blocks.js new file mode 100644 index 00000000000..dd35afda672 --- /dev/null +++ b/ecmascript/parser/tests/span/js/decl/static-blocks.js @@ -0,0 +1,5 @@ +class Foo { + static { + 1 + 1; + } +} diff --git a/ecmascript/parser/tests/span/js/decl/static-blocks.js.spans b/ecmascript/parser/tests/span/js/decl/static-blocks.js.spans new file mode 100644 index 00000000000..19255884c4c --- /dev/null +++ b/ecmascript/parser/tests/span/js/decl/static-blocks.js.spans @@ -0,0 +1,143 @@ +warning: Module + --> $DIR/tests/span/js/decl/static-blocks.js:1:1 + | +1 | / class Foo { +2 | | static { +3 | | 1 + 1; +4 | | } +5 | | } + | |_^ + +warning: ModuleItem + --> $DIR/tests/span/js/decl/static-blocks.js:1:1 + | +1 | / class Foo { +2 | | static { +3 | | 1 + 1; +4 | | } +5 | | } + | |_^ + +warning: Stmt + --> $DIR/tests/span/js/decl/static-blocks.js:1:1 + | +1 | / class Foo { +2 | | static { +3 | | 1 + 1; +4 | | } +5 | | } + | |_^ + +warning: Decl + --> $DIR/tests/span/js/decl/static-blocks.js:1:1 + | +1 | / class Foo { +2 | | static { +3 | | 1 + 1; +4 | | } +5 | | } + | |_^ + +warning: ClassDecl + --> $DIR/tests/span/js/decl/static-blocks.js:1:1 + | +1 | / class Foo { +2 | | static { +3 | | 1 + 1; +4 | | } +5 | | } + | |_^ + +warning: Ident + --> $DIR/tests/span/js/decl/static-blocks.js:1:7 + | +1 | class Foo { + | ^^^ + +warning: Class + --> $DIR/tests/span/js/decl/static-blocks.js:1:1 + | +1 | / class Foo { +2 | | static { +3 | | 1 + 1; +4 | | } +5 | | } + | |_^ + +warning: ClassMember + --> $DIR/tests/span/js/decl/static-blocks.js:2:5 + | +2 | / static { +3 | | 1 + 1; +4 | | } + | |_____^ + +warning: BlockStmt + --> $DIR/tests/span/js/decl/static-blocks.js:2:12 + | +2 | static { + | ____________^ +3 | | 1 + 1; +4 | | } + | |_____^ + +warning: Stmt + --> $DIR/tests/span/js/decl/static-blocks.js:3:9 + | +3 | 1 + 1; + | ^^^^^^ + +warning: ExprStmt + --> $DIR/tests/span/js/decl/static-blocks.js:3:9 + | +3 | 1 + 1; + | ^^^^^^ + +warning: Expr + --> $DIR/tests/span/js/decl/static-blocks.js:3:9 + | +3 | 1 + 1; + | ^^^^^ + +warning: BinExpr + --> $DIR/tests/span/js/decl/static-blocks.js:3:9 + | +3 | 1 + 1; + | ^^^^^ + +warning: Expr + --> $DIR/tests/span/js/decl/static-blocks.js:3:9 + | +3 | 1 + 1; + | ^ + +warning: Lit + --> $DIR/tests/span/js/decl/static-blocks.js:3:9 + | +3 | 1 + 1; + | ^ + +warning: Number + --> $DIR/tests/span/js/decl/static-blocks.js:3:9 + | +3 | 1 + 1; + | ^ + +warning: Expr + --> $DIR/tests/span/js/decl/static-blocks.js:3:13 + | +3 | 1 + 1; + | ^ + +warning: Lit + --> $DIR/tests/span/js/decl/static-blocks.js:3:13 + | +3 | 1 + 1; + | ^ + +warning: Number + --> $DIR/tests/span/js/decl/static-blocks.js:3:13 + | +3 | 1 + 1; + | ^ +