fix(es/parser): Fix parsing of decorators (#3449)

swc_ecma_parser:
 - Parse decorators using `parse_subscripts`.
This commit is contained in:
Donny/강동윤 2022-02-04 17:54:03 +09:00 committed by GitHub
parent 8b7c38c80c
commit 5a806c5b81
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 438 additions and 77 deletions

View File

@ -0,0 +1,15 @@
{
"jsc": {
"parser": {
"syntax": "typescript",
"decorators": true
},
"transform": {
"legacyDecorator": true,
"decoratorMetadata": true
}
},
"module": {
"type": "commonjs"
}
}

View File

@ -0,0 +1,6 @@
import * as joiful from 'joiful';
class Schema {
@joiful.string().guid().required()
public id: string;
}

View File

@ -0,0 +1,79 @@
"use strict";
var joiful = _interopRequireWildcard(require("joiful"));
function _applyDecoratedDescriptor(target, property, decorators, descriptor, context) {
var desc = {};
Object.keys(descriptor).forEach(function(key) {
desc[key] = descriptor[key];
});
desc.enumerable = !!desc.enumerable;
desc.configurable = !!desc.configurable;
if ("value" in desc || desc.initializer) {
desc.writable = true;
}
desc = decorators.slice().reverse().reduce(function(desc, decorator) {
return decorator ? decorator(target, property, desc) || desc : desc;
}, desc);
if (context && desc.initializer !== void 0) {
desc.value = desc.initializer ? desc.initializer.call(context) : void 0;
desc.initializer = undefined;
}
var own = Object.getOwnPropertyDescriptor(target, property);
if (own && (own.get || own.set)) {
delete desc.writable;
delete desc.initializer;
}
if (desc.initializer === void 0) {
Object.defineProperty(target, property, desc);
desc = null;
}
return desc;
}
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _initializerDefineProperty(target, property, descriptor, context) {
if (!descriptor) return;
Object.defineProperty(target, property, {
enumerable: descriptor.enumerable,
configurable: descriptor.configurable,
writable: descriptor.writable,
value: descriptor.initializer ? descriptor.initializer.call(context) : void 0
});
}
function _interopRequireWildcard(obj) {
if (obj && obj.__esModule) {
return obj;
} else {
var newObj = {};
if (obj != null) {
for(var key in obj){
if (Object.prototype.hasOwnProperty.call(obj, key)) {
var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {};
if (desc.get || desc.set) {
Object.defineProperty(newObj, key, desc);
} else {
newObj[key] = obj[key];
}
}
}
}
newObj.default = obj;
return newObj;
}
}
var _class, _descriptor, _dec, _dec1;
var Schema = ((_class = function Schema() {
"use strict";
_classCallCheck(this, Schema);
_initializerDefineProperty(this, "id", _descriptor, this);
}) || _class, _dec = joiful.string().guid().required(), _dec1 = typeof Reflect !== "undefined" && typeof Reflect.metadata === "function" && Reflect.metadata("design:type", String), _descriptor = _applyDecoratedDescriptor(_class.prototype, "id", [
_dec,
_dec1
], {
configurable: true,
enumerable: true,
writable: true,
initializer: void 0
}), _class);

View File

@ -286,7 +286,7 @@ fn issue_414() {
fn issue_415() {
let s = file("tests/projects/issue-415/input.js").unwrap();
assert!(s.replace(" ", "").contains("return(/*#__PURE__*/"));
assert!(s.replace(' ', "").contains("return(/*#__PURE__*/"));
}
#[test]
@ -313,7 +313,7 @@ fn issue_468() {
fn issue_528() {
let f = file("tests/projects/issue-528/input.js")
.unwrap()
.replace(" ", "");
.replace(' ', "");
let f = f.trim();
println!("{}", f);
@ -335,7 +335,7 @@ b)
fn env_entry_chrome_49() {
let f = file("tests/env/entry/chrome-49/input.js")
.unwrap()
.replace(" ", "");
.replace(' ', "");
let f = f.trim();
println!("{}", f);
@ -347,7 +347,7 @@ fn env_entry_chrome_49() {
fn env_entry_chrome_71() {
let f = file("tests/env/entry/chrome-71/input.js")
.unwrap()
.replace(" ", "");
.replace(' ', "");
let f = f.trim();
println!("{}", f);
@ -359,7 +359,7 @@ fn env_entry_chrome_71() {
fn env_query_chrome_71() {
let f = file("tests/env/query/chrome-71/input.js")
.unwrap()
.replace(" ", "");
.replace(' ', "");
let f = f.trim();
println!("{}", f);

View File

@ -192,6 +192,7 @@ impl<'a, I: Tokens> Parser<I> {
if !self.syntax().decorators() {
return Ok(vec![]);
}
trace_cur!(self, parse_decorators);
let mut decorators = vec![];
let start = cur_pos!(self);
@ -221,6 +222,7 @@ impl<'a, I: Tokens> Parser<I> {
fn parse_decorator(&mut self) -> PResult<Decorator> {
let start = cur_pos!(self);
trace_cur!(self, parse_decorator);
assert_and_bump!(self, '@');
@ -229,24 +231,12 @@ impl<'a, I: Tokens> Parser<I> {
expect!(self, ')');
expr
} else {
let mut expr = self
let expr = self
.parse_ident(false, false)
.map(Expr::from)
.map(Box::new)?;
while eat!(self, '.') {
let ident = self.parse_ident(true, true)?;
let span = Span::new(start, expr.span().hi(), Default::default());
expr = Box::new(Expr::Member(MemberExpr {
span,
obj: expr,
prop: MemberProp::Ident(ident),
}));
}
expr
self.parse_subscripts(Callee::Expr(expr), false, true)?
};
let expr = self.parse_maybe_decorator_args(expr)?;

View File

@ -506,7 +506,7 @@ impl<'a, I: Tokens> Parser<I> {
kind: MetaPropKind::NewTarget,
}));
return self.parse_subscripts(Callee::Expr(expr), true);
return self.parse_subscripts(Callee::Expr(expr), true, false);
}
unexpected!(self, "target")
@ -542,7 +542,7 @@ impl<'a, I: Tokens> Parser<I> {
// We should parse subscripts for MemberExpression.
// Because it's left recursive.
return self.parse_subscripts(new_expr, true);
return self.parse_subscripts(new_expr, true, false);
}
// Parsed with 'NewExpression' production.
@ -559,18 +559,18 @@ impl<'a, I: Tokens> Parser<I> {
let base = Callee::Super(Super {
span: span!(self, start),
});
return self.parse_subscripts(base, true);
return self.parse_subscripts(base, true, false);
}
if eat!(self, "import") {
let base = Callee::Import(Import {
span: span!(self, start),
});
return self.parse_subscripts(base, true);
return self.parse_subscripts(base, true, false);
}
let obj = self.parse_primary_expr()?;
return_if_arrow!(self, obj);
self.parse_subscripts(Callee::Expr(obj), true)
self.parse_subscripts(Callee::Expr(obj), true, false)
}
/// Parse `NewExpression`.
@ -973,10 +973,15 @@ impl<'a, I: Tokens> Parser<I> {
})
}
fn parse_subscripts(&mut self, mut obj: Callee, no_call: bool) -> PResult<Box<Expr>> {
pub(super) fn parse_subscripts(
&mut self,
mut obj: Callee,
no_call: bool,
no_computed_member: bool,
) -> PResult<Box<Expr>> {
let start = obj.span().lo;
loop {
obj = match self.parse_subscript(start, obj, no_call)? {
obj = match self.parse_subscript(start, obj, no_call, no_computed_member)? {
(expr, false) => return Ok(expr),
(expr, true) => Callee::Expr(expr),
}
@ -989,6 +994,7 @@ impl<'a, I: Tokens> Parser<I> {
start: BytePos,
mut obj: Callee,
no_call: bool,
no_computed_member: bool,
) -> PResult<(Box<Expr>, bool)> {
let _ = cur!(self, false);
@ -1114,12 +1120,13 @@ impl<'a, I: Tokens> Parser<I> {
}
// $obj[name()]
if (question_dot_token.is_some()
&& is!(self, '.')
&& peeked_is!(self, '[')
&& eat!(self, '.')
&& eat!(self, '['))
|| eat!(self, '[')
if !no_computed_member
&& ((question_dot_token.is_some()
&& is!(self, '.')
&& peeked_is!(self, '[')
&& eat!(self, '.')
&& eat!(self, '['))
|| eat!(self, '['))
{
let bracket_lo = self.input.prev_span().lo;
let prop = self.include_in_expr(true).parse_expr()?;
@ -1338,13 +1345,13 @@ impl<'a, I: Tokens> Parser<I> {
let obj = Callee::Super(Super {
span: span!(self, start),
});
return self.parse_subscripts(obj, false);
return self.parse_subscripts(obj, false, false);
}
if eat!(self, "import") {
let obj = Callee::Import(Import {
span: span!(self, start),
});
return self.parse_subscripts(obj, false);
return self.parse_subscripts(obj, false, false);
}
let callee = self.parse_new_expr()?;
@ -1401,7 +1408,7 @@ impl<'a, I: Tokens> Parser<I> {
type_args,
}));
return self.parse_subscripts(Callee::Expr(call_expr), false);
return self.parse_subscripts(Callee::Expr(call_expr), false, false);
}
if type_args.is_some() {
// This fails
@ -1797,7 +1804,7 @@ impl<'a, I: Tokens> Parser<I> {
type_args: Default::default(),
}));
self.parse_subscripts(Callee::Expr(import), true)
self.parse_subscripts(Callee::Expr(import), true, false)
}
pub(super) fn check_assign_target(&mut self, expr: &Expr, deny_call: bool) {

View File

@ -355,6 +355,16 @@ macro_rules! syntax_error {
($p:expr, $span:expr, $err:expr) => {{
let err = make_error!($p, $span, $err);
if cfg!(feature = "debug") {
tracing::error!(
"Syntax error called from {}:{}:{}\nCurrent token = {:?}",
file!(),
line!(),
column!(),
$p.input.cur()
);
}
return Err(err.into());
}};
}

View File

@ -50,7 +50,25 @@
"optional": false
},
"arguments": [],
"typeArguments": null
"typeArguments": {
"type": "TsTypeParameterInstantiation",
"span": {
"start": 10,
"end": 18,
"ctxt": 0
},
"params": [
{
"type": "TsKeywordType",
"span": {
"start": 11,
"end": 17,
"ctxt": 0
},
"kind": "string"
}
]
}
}
}
],

View File

@ -0,0 +1,6 @@
import * as joiful from 'joiful';
class Schema {
@joiful.string().guid().required()
public id: string;
}

View File

@ -0,0 +1,230 @@
{
"type": "Module",
"span": {
"start": 0,
"end": 113,
"ctxt": 0
},
"body": [
{
"type": "ImportDeclaration",
"span": {
"start": 0,
"end": 33,
"ctxt": 0
},
"specifiers": [
{
"type": "ImportNamespaceSpecifier",
"span": {
"start": 7,
"end": 18,
"ctxt": 0
},
"local": {
"type": "Identifier",
"span": {
"start": 12,
"end": 18,
"ctxt": 0
},
"value": "joiful",
"optional": false
}
}
],
"source": {
"type": "StringLiteral",
"span": {
"start": 24,
"end": 32,
"ctxt": 0
},
"value": "joiful",
"hasEscape": false,
"kind": {
"type": "normal",
"containsQuote": true
}
},
"typeOnly": false,
"asserts": null
},
{
"type": "ClassDeclaration",
"identifier": {
"type": "Identifier",
"span": {
"start": 41,
"end": 47,
"ctxt": 0
},
"value": "Schema",
"optional": false
},
"declare": false,
"span": {
"start": 35,
"end": 113,
"ctxt": 0
},
"decorators": [],
"body": [
{
"type": "ClassProperty",
"span": {
"start": 54,
"end": 111,
"ctxt": 0
},
"key": {
"type": "Identifier",
"span": {
"start": 100,
"end": 102,
"ctxt": 0
},
"value": "id",
"optional": false
},
"value": null,
"typeAnnotation": {
"type": "TsTypeAnnotation",
"span": {
"start": 102,
"end": 110,
"ctxt": 0
},
"typeAnnotation": {
"type": "TsKeywordType",
"span": {
"start": 104,
"end": 110,
"ctxt": 0
},
"kind": "string"
}
},
"isStatic": false,
"decorators": [
{
"type": "Decorator",
"span": {
"start": 54,
"end": 88,
"ctxt": 0
},
"expression": {
"type": "CallExpression",
"span": {
"start": 55,
"end": 88,
"ctxt": 0
},
"callee": {
"type": "MemberExpression",
"span": {
"start": 55,
"end": 86,
"ctxt": 0
},
"object": {
"type": "CallExpression",
"span": {
"start": 55,
"end": 77,
"ctxt": 0
},
"callee": {
"type": "MemberExpression",
"span": {
"start": 55,
"end": 75,
"ctxt": 0
},
"object": {
"type": "CallExpression",
"span": {
"start": 55,
"end": 70,
"ctxt": 0
},
"callee": {
"type": "MemberExpression",
"span": {
"start": 55,
"end": 68,
"ctxt": 0
},
"object": {
"type": "Identifier",
"span": {
"start": 55,
"end": 61,
"ctxt": 0
},
"value": "joiful",
"optional": false
},
"property": {
"type": "Identifier",
"span": {
"start": 62,
"end": 68,
"ctxt": 0
},
"value": "string",
"optional": false
}
},
"arguments": [],
"typeArguments": null
},
"property": {
"type": "Identifier",
"span": {
"start": 71,
"end": 75,
"ctxt": 0
},
"value": "guid",
"optional": false
}
},
"arguments": [],
"typeArguments": null
},
"property": {
"type": "Identifier",
"span": {
"start": 78,
"end": 86,
"ctxt": 0
},
"value": "required",
"optional": false
}
},
"arguments": [],
"typeArguments": null
}
}
],
"accessibility": "public",
"isAbstract": false,
"isOptional": false,
"isOverride": false,
"readonly": false,
"declare": false,
"definite": false
}
],
"superClass": null,
"isAbstract": false,
"typeParams": null,
"superTypeParams": null,
"implements": []
}
],
"interpreter": null
}

View File

@ -9132,22 +9132,22 @@
"expression": {
"type": "CallExpression",
"span": {
"start": 7761,
"start": 7762,
"end": 7819,
"ctxt": 0
},
"callee": {
"type": "MemberExpression",
"span": {
"start": 7761,
"end": 7767,
"start": 7762,
"end": 7783,
"ctxt": 0
},
"object": {
"type": "MemberExpression",
"span": {
"start": 7761,
"end": 7767,
"start": 7762,
"end": 7772,
"ctxt": 0
},
"object": {
@ -9987,22 +9987,22 @@
"expression": {
"type": "CallExpression",
"span": {
"start": 8295,
"start": 8296,
"end": 8387,
"ctxt": 0
},
"callee": {
"type": "MemberExpression",
"span": {
"start": 8295,
"end": 8301,
"start": 8296,
"end": 8317,
"ctxt": 0
},
"object": {
"type": "MemberExpression",
"span": {
"start": 8295,
"end": 8301,
"start": 8296,
"end": 8306,
"ctxt": 0
},
"object": {
@ -10855,22 +10855,22 @@
"expression": {
"type": "CallExpression",
"span": {
"start": 8871,
"start": 8872,
"end": 8968,
"ctxt": 0
},
"callee": {
"type": "MemberExpression",
"span": {
"start": 8871,
"end": 8877,
"start": 8872,
"end": 8893,
"ctxt": 0
},
"object": {
"type": "MemberExpression",
"span": {
"start": 8871,
"end": 8877,
"start": 8872,
"end": 8882,
"ctxt": 0
},
"object": {
@ -11437,22 +11437,22 @@
"expression": {
"type": "CallExpression",
"span": {
"start": 9268,
"start": 9269,
"end": 9404,
"ctxt": 0
},
"callee": {
"type": "MemberExpression",
"span": {
"start": 9268,
"end": 9274,
"start": 9269,
"end": 9290,
"ctxt": 0
},
"object": {
"type": "MemberExpression",
"span": {
"start": 9268,
"end": 9274,
"start": 9269,
"end": 9279,
"ctxt": 0
},
"object": {
@ -12364,22 +12364,22 @@
"expression": {
"type": "CallExpression",
"span": {
"start": 9930,
"start": 9931,
"end": 9988,
"ctxt": 0
},
"callee": {
"type": "MemberExpression",
"span": {
"start": 9930,
"end": 9936,
"start": 9931,
"end": 9952,
"ctxt": 0
},
"object": {
"type": "MemberExpression",
"span": {
"start": 9930,
"end": 9936,
"start": 9931,
"end": 9941,
"ctxt": 0
},
"object": {
@ -13219,22 +13219,22 @@
"expression": {
"type": "CallExpression",
"span": {
"start": 10468,
"start": 10469,
"end": 10531,
"ctxt": 0
},
"callee": {
"type": "MemberExpression",
"span": {
"start": 10468,
"end": 10474,
"start": 10469,
"end": 10490,
"ctxt": 0
},
"object": {
"type": "MemberExpression",
"span": {
"start": 10468,
"end": 10474,
"start": 10469,
"end": 10479,
"ctxt": 0
},
"object": {
@ -13788,22 +13788,22 @@
"expression": {
"type": "CallExpression",
"span": {
"start": 10837,
"start": 10838,
"end": 10937,
"ctxt": 0
},
"callee": {
"type": "MemberExpression",
"span": {
"start": 10837,
"end": 10843,
"start": 10838,
"end": 10859,
"ctxt": 0
},
"object": {
"type": "MemberExpression",
"span": {
"start": 10837,
"end": 10843,
"start": 10838,
"end": 10848,
"ctxt": 0
},
"object": {
@ -14656,22 +14656,22 @@
"expression": {
"type": "CallExpression",
"span": {
"start": 11425,
"start": 11426,
"end": 11530,
"ctxt": 0
},
"callee": {
"type": "MemberExpression",
"span": {
"start": 11425,
"end": 11431,
"start": 11426,
"end": 11447,
"ctxt": 0
},
"object": {
"type": "MemberExpression",
"span": {
"start": 11425,
"end": 11431,
"start": 11426,
"end": 11436,
"ctxt": 0
},
"object": {