Skip to content

Commit 91a9b98

Browse files
mvitousekmeta-codesync[bot]
authored andcommitted
Add async component syntax support
Summary: Add `async component` syntax support to the Hermes C++ parser, hermes-parser JS package, and all associated tests. AST: Add `async` boolean field (default false) to `ComponentDeclaration` nodes in ESTree.def. Parser: Add `checkAsyncComponentFlow()` lookahead, update `parseDeclaration()` and export handlers to recognize `async component` variants. The `parseComponentDeclarationFlow` function gains an `isAsync` parameter. `declare async component` is rejected with a parse error directing users to use `declare component` instead. Updates all existing component syntax FileCheck tests for consistency. Adds new tests for async component. Updates hermes-parser JS tests and snapshots. Updates flowtest tree.json snapshots for consistency. Reviewed By: avp Differential Revision: D93299448 fbshipit-source-id: 0f17df8c8860831538b50feff704a3751e330e57
1 parent 703589f commit 91a9b98

15 files changed

Lines changed: 484 additions & 40 deletions

File tree

include/hermes/AST/ESTree.def

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,14 @@ ESTREE_IGNORE_IF_EMPTY(FunctionDeclaration, predicate)
7777

7878
#if HERMES_PARSE_FLOW
7979

80-
ESTREE_NODE_5_ARGS(
80+
ESTREE_NODE_6_ARGS(
8181
ComponentDeclaration, FunctionLike,
8282
NodePtr, id, false,
8383
NodeList, params, false,
8484
NodePtr, body, false,
8585
NodePtr, typeParameters, true,
86-
NodePtr, rendersType, true)
86+
NodePtr, rendersType, true,
87+
NodeBoolean, async, false)
8788
ESTREE_IGNORE_IF_EMPTY(ComponentDeclaration, typeParameters)
8889
ESTREE_IGNORE_IF_EMPTY(ComponentDeclaration, rendersType)
8990

lib/Parser/JSParserImpl-flow.cpp

Lines changed: 75 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@ Optional<ESTree::Node *> JSParserImpl::parseFlowDeclaration() {
2222
assert(checkDeclaration());
2323
SMLoc start = tok_->getStartLoc();
2424

25+
if (context_.getParseFlowComponentSyntax() && check(asyncIdent_) &&
26+
checkAsyncComponentFlow()) {
27+
advance(); // consume 'async'
28+
return parseComponentDeclarationFlow(
29+
start, /* declare */ false, /* isAsync */ true);
30+
}
31+
2532
if (context_.getParseFlowComponentSyntax() &&
2633
checkComponentDeclarationFlow()) {
2734
return parseComponentDeclarationFlow(start, /* declare */ false);
@@ -101,6 +108,17 @@ Optional<ESTree::Node *> JSParserImpl::parseDeclareFLow(SMLoc start) {
101108
return parseDeclareHookFlow(start);
102109
}
103110

111+
if (context_.getParseFlowComponentSyntax() && check(asyncIdent_) &&
112+
checkAsyncComponentFlow()) {
113+
error(
114+
tok_->getStartLoc(),
115+
"`async` is not supported for declared components. "
116+
"Use `declare component` instead.");
117+
advance(); // consume 'async'
118+
return parseComponentDeclarationFlow(
119+
start, /* declare */ true, /* isAsync */ true);
120+
}
121+
104122
if (context_.getParseFlowComponentSyntax() &&
105123
checkComponentDeclarationFlow()) {
106124
return parseComponentDeclarationFlow(start, /* declare */ true);
@@ -167,9 +185,23 @@ bool JSParserImpl::checkComponentDeclarationFlow() {
167185
return optNext.hasValue() && *optNext == TokenKind::identifier;
168186
}
169187

188+
bool JSParserImpl::checkAsyncComponentFlow() {
189+
// async [no LineTerminator here] component
190+
// ^
191+
// Callers must already check check(asyncIdent_).
192+
assert(check(asyncIdent_));
193+
JSLexer::SavePoint savePoint{&lexer_};
194+
advance();
195+
bool result =
196+
!lexer_.isNewLineBeforeCurrentToken() && checkComponentDeclarationFlow();
197+
savePoint.restore();
198+
return result;
199+
}
200+
170201
Optional<ESTree::Node *> JSParserImpl::parseComponentDeclarationFlow(
171202
SMLoc start,
172-
bool declare) {
203+
bool declare,
204+
bool isAsync) {
173205
// component
174206
assert(check(componentIdent_));
175207
advance();
@@ -247,7 +279,7 @@ Optional<ESTree::Node *> JSParserImpl::parseComponentDeclarationFlow(
247279
SaveStrictModeAndSeenDirectives saveStrictModeAndSeenDirectives{this};
248280

249281
auto parsedBody = parseFunctionBody(
250-
Param{}, false, false, false, JSLexer::AllowRegExp, true);
282+
Param{}, false, false, isAsync, JSLexer::AllowRegExp, true);
251283
if (!parsedBody)
252284
return None;
253285
auto *body = parsedBody.getValue();
@@ -256,7 +288,12 @@ Optional<ESTree::Node *> JSParserImpl::parseComponentDeclarationFlow(
256288
start,
257289
body,
258290
new (context_) ESTree::ComponentDeclarationNode(
259-
*optId, std::move(paramList), body, typeParams, rendersType));
291+
*optId,
292+
std::move(paramList),
293+
body,
294+
typeParams,
295+
rendersType,
296+
isAsync));
260297
}
261298

262299
bool JSParserImpl::parseComponentParametersFlow(
@@ -2081,6 +2118,23 @@ Optional<ESTree::Node *> JSParserImpl::parseDeclareExportFlow(SMLoc start) {
20812118
new (context_) ESTree::DeclareExportDeclarationNode(
20822119
*optFunc, {}, nullptr, true));
20832120
}
2121+
if (context_.getParseFlowComponentSyntax() && check(asyncIdent_) &&
2122+
checkAsyncComponentFlow()) {
2123+
error(
2124+
tok_->getStartLoc(),
2125+
"`async` is not supported for declared components. "
2126+
"Use `declare component` instead.");
2127+
advance(); // consume 'async'
2128+
auto optComponent = parseComponentDeclarationFlow(
2129+
start, /* declare */ true, /* isAsync */ true);
2130+
if (!optComponent)
2131+
return None;
2132+
return setLocation(
2133+
start,
2134+
*optComponent,
2135+
new (context_) ESTree::DeclareExportDeclarationNode(
2136+
*optComponent, {}, nullptr, true));
2137+
}
20842138
if (context_.getParseFlowComponentSyntax() &&
20852139
checkComponentDeclarationFlow()) {
20862140
auto optComponent =
@@ -2148,6 +2202,24 @@ Optional<ESTree::Node *> JSParserImpl::parseDeclareExportFlow(SMLoc start) {
21482202
*optClass, {}, nullptr, false));
21492203
}
21502204

2205+
if (context_.getParseFlowComponentSyntax() && check(asyncIdent_) &&
2206+
checkAsyncComponentFlow()) {
2207+
error(
2208+
tok_->getStartLoc(),
2209+
"`async` is not supported for declared components. "
2210+
"Use `declare component` instead.");
2211+
advance(); // consume 'async'
2212+
auto optComponent = parseComponentDeclarationFlow(
2213+
start, /* declare */ true, /* isAsync */ true);
2214+
if (!optComponent)
2215+
return None;
2216+
return setLocation(
2217+
start,
2218+
*optComponent,
2219+
new (context_) ESTree::DeclareExportDeclarationNode(
2220+
*optComponent, {}, nullptr, false));
2221+
}
2222+
21512223
if (context_.getParseFlowComponentSyntax() &&
21522224
checkComponentDeclarationFlow()) {
21532225
auto optComponent =

lib/Parser/JSParserImpl.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -791,7 +791,8 @@ Optional<ESTree::Node *> JSParserImpl::parseDeclaration(Param param) {
791791

792792
assert(checkDeclaration() && "invalid start for declaration");
793793

794-
if (check(TokenKind::rw_function) || check(asyncIdent_)) {
794+
if (check(TokenKind::rw_function) ||
795+
(check(asyncIdent_) && checkAsyncFunction())) {
795796
auto fdecl = parseFunctionDeclaration(Param{});
796797
if (!fdecl)
797798
return None;
@@ -6747,6 +6748,19 @@ Optional<ESTree::Node *> JSParserImpl::parseExportDeclaration() {
67476748
*optClassDecl,
67486749
new (context_) ESTree::ExportDefaultDeclarationNode(*optClassDecl));
67496750
#if HERMES_PARSE_FLOW
6751+
} else if (
6752+
context_.getParseFlow() && context_.getParseFlowComponentSyntax() &&
6753+
check(asyncIdent_) && checkAsyncComponentFlow()) {
6754+
SMLoc compStart = advance().Start;
6755+
auto optComponent = parseComponentDeclarationFlow(
6756+
compStart, /* declare */ false, /* isAsync */ true);
6757+
if (!optComponent) {
6758+
return None;
6759+
}
6760+
return setLocation(
6761+
startLoc,
6762+
*optComponent,
6763+
new (context_) ESTree::ExportDefaultDeclarationNode(*optComponent));
67506764
} else if (
67516765
context_.getParseFlow() && context_.getParseFlowComponentSyntax() &&
67526766
checkComponentDeclarationFlow()) {

lib/Parser/JSParserImpl.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -539,7 +539,8 @@ class JSParserImpl {
539539
#if HERMES_PARSE_FLOW
540540
if (context_.getParseFlow()) {
541541
if (context_.getParseFlowComponentSyntax() &&
542-
checkComponentDeclarationFlow()) {
542+
(checkComponentDeclarationFlow() ||
543+
(check(asyncIdent_) && checkAsyncComponentFlow()))) {
543544
return true;
544545
}
545546
if (context_.getParseFlowComponentSyntax() &&
@@ -1184,9 +1185,11 @@ class JSParserImpl {
11841185
Optional<ESTree::Node *> parseFlowDeclaration();
11851186
Optional<ESTree::Node *> parseDeclareFLow(SMLoc start);
11861187
bool checkComponentDeclarationFlow();
1188+
bool checkAsyncComponentFlow();
11871189
Optional<ESTree::Node *> parseComponentDeclarationFlow(
11881190
SMLoc start,
1189-
bool declare);
1191+
bool declare,
1192+
bool isAsync = false);
11901193
bool checkHookDeclarationFlow();
11911194
Optional<ESTree::Node *> parseHookDeclarationFlow(SMLoc start);
11921195

0 commit comments

Comments
 (0)