Bug 1784513 - handle decorator member expressions with `.` in them; r=mgaudet

Currently we only support `IdentifierName`, but the grammar allows for multiple
`IdentifierName`s separated by `.`:

`DecoratorMemberExpression[?Yield, ?Await] . IdentifierName`

Differential Revision: https://phabricator.services.mozilla.com/D154814
This commit is contained in:
Dan Minor 2022-08-17 12:39:21 +00:00
Родитель e3b648be1d
Коммит 313af2f09a
3 изменённых файлов: 49 добавлений и 11 удалений

Просмотреть файл

@ -389,7 +389,7 @@ MSG_DEF(JSMSG_DUPLICATE_ASSERT_KEY, 1, JSEXN_SYNTAXERR, "duplicate assert key
MSG_DEF(JSMSG_COLON_AFTER_ASSERT_KEY, 0, JSEXN_SYNTAXERR, "missing : after assert key")
MSG_DEF(JSMSG_ASSERT_STRING_LITERAL, 0, JSEXN_SYNTAXERR, "expected string literal")
MSG_DEF(JSMSG_ASSERT_KEY_EXPECTED, 0, JSEXN_SYNTAXERR, "expected assertion key")
MSG_DEF(JSMSG_DECORATOR_NAME_EXPECTED, 0, JSEXN_SYNTAXERR, "expected decorator name after @")
MSG_DEF(JSMSG_DECORATOR_NAME_EXPECTED, 0, JSEXN_SYNTAXERR, "expected property name in decorator expression")
MSG_DEF(JSMSG_CLASS_EXPECTED, 0, JSEXN_SYNTAXERR, "expected class")
// UTF-8 source text encoding errors

Просмотреть файл

@ -7671,25 +7671,53 @@ GeneralParser<ParseHandler, Unit>::decoratorList(YieldHandling yieldHandling) {
return null();
}
// Handle DecoratorMemberExpression
decorator = handler_.newName(name, pos());
// Ok, this DecoratorMemberExpression is actually a list of
// Identifiers separated by `.`
if (tt == TokenKind::Dot) {
ListNodeType ids =
handler_.newList(ParseNodeKind::DecoratorList, pos());
handler_.addList(ids, decorator);
for (;;) {
if (!tokenStream.getToken(&tt)) {
return null();
}
// Reject invalid or missing identifiers, like dec1.(
if (!(tt == TokenKind::Name || TokenKindIsContextualKeyword(tt))) {
error(JSMSG_DECORATOR_NAME_EXPECTED);
return null();
}
TaggedParserAtomIndex name = anyChars.currentName();
Node id = handler_.newName(name, pos());
handler_.addList(ids, id);
if (!tokenStream.getToken(&tt)) {
return null();
}
if (tt != TokenKind::Dot) {
break;
}
}
decorator = ids;
}
// We've hit a `(`, so it's actually a DecoratorCallExpression
if (tt == TokenKind::LeftParen) {
// Handle DecoratorCallExpression
Node decoratorName = handler_.newName(name, pos());
bool isSpread = false;
Node args = argumentList(yieldHandling, &isSpread);
if (!args) {
return null();
}
decorator = handler_.newCall(decoratorName, args,
decorator = handler_.newCall(decorator, args,
isSpread ? JSOp::SpreadCall : JSOp::Call);
if (!tokenStream.getToken(&tt)) {
return null();
}
} else {
// Handle DecoratorMemberExpression
// TODO: Bug 1784513, handle decorator member expressions with `.` in
// them.
decorator = handler_.newName(name, pos());
}
}
MOZ_ASSERT(decorator, "Decorator should exist");

Просмотреть файл

@ -18,6 +18,15 @@ Reflect.parse("@dec1('a') @(() => {}) @dec3 class c {@((a, b, c) => {}) @dec2('a
Reflect.parse("x = @dec class { #x }");
Reflect.parse("x = (class A { }, @dec class { })");
Reflect.parse("@dec1 class A extends @dec2 class B extends @dec3 class {} {} {}");
Reflect.parse("class c {@dec1.dec2.dec3 method() {};}");
Reflect.parse("class c {@dec1 @dec2.dec3.dec4 @dec5 method() {};}");
Reflect.parse("class c {@dec1('a') @dec2.dec3.dec4 @dec5 method() {};}");
Reflect.parse("class c {@dec1('a') @dec2.dec3.dec4('b', 'c') @dec5 method() {};}");
Reflect.parse("class c {@dec1('a') @dec2.dec3.dec4('b', 'c') @dec5.dec6 method() {};}");
Reflect.parse("@dec1.dec2 class c {}");
Reflect.parse("@dec1.dec2 @dec3.dec4 @dec5 class c {}");
Reflect.parse("@dec1.dec2('a') @(() => {}) @dec4 class c {}");
Reflect.parse("@dec1.dec2('a') @(() => {}) @dec4 class c {@((a, b, c) => {}) @dec5.dec6('a', 'b') @dec7 method(a, b) {};}");
assertThrowsInstanceOf(() => Reflect.parse("class c {@ method() {};}"), SyntaxError);
assertThrowsInstanceOf(() => Reflect.parse("class c {@((a, b, c => {}) method(a, b) {};}"), SyntaxError);
@ -27,5 +36,6 @@ assertThrowsInstanceOf(() => Reflect.parse("@dec1 f(a) {}"), SyntaxError);
assertThrowsInstanceOf(() => Reflect.parse("@dec1 () => {}"), SyntaxError);
assertThrowsInstanceOf(() => Reflect.parse("@class class { x; }"), SyntaxError);
assertThrowsInstanceOf(() => Reflect.parse("@for class { x; }"), SyntaxError);
if (typeof reportCompare === "function") reportCompare(0, 0);
assertThrowsInstanceOf(() => Reflect.parse("class c {@dec1. method() {};}"), SyntaxError);
assertThrowsInstanceOf(() => Reflect.parse("@dec1. class c {method() {};}"), SyntaxError);
assertThrowsInstanceOf(() => Reflect.parse("@dec1.(a) class c {method() {};}"), SyntaxError);