in lib/Parser/JSParserImpl.cpp [6341:6525]
Optional<ESTree::Node *> JSParserImpl::parseExportDeclaration() {
assert(
check(TokenKind::rw_export) &&
"parseExportDeclaration requires 'export'");
SMLoc startLoc = advance().Start;
#if HERMES_PARSE_FLOW
if (context_.getParseFlow() && check(typeIdent_)) {
return parseExportTypeDeclarationFlow(startLoc);
}
#endif
if (checkAndEat(TokenKind::star)) {
// export * FromClause;
// export * as IdentifierName FromClause;
ESTree::Node *exportAs = nullptr;
if (checkAndEat(asIdent_)) {
// export * as IdentifierName FromClause;
// ^
if (!check(TokenKind::identifier) && !tok_->isResWord()) {
errorExpected(
TokenKind::identifier,
"in export clause",
"start of export",
startLoc);
return None;
}
exportAs = setLocation(
tok_,
tok_,
new (context_) ESTree::IdentifierNode(
tok_->getResWordOrIdentifier(), nullptr, false));
advance();
}
auto optFromClause = parseFromClause();
if (!optFromClause) {
return None;
}
if (!eatSemi()) {
return None;
}
if (exportAs) {
ESTree::NodeList specifiers{};
specifiers.push_back(*setLocation(
startLoc,
getPrevTokenEndLoc(),
new (context_) ESTree::ExportNamespaceSpecifierNode(exportAs)));
return setLocation(
startLoc,
getPrevTokenEndLoc(),
new (context_) ESTree::ExportNamedDeclarationNode(
nullptr, std::move(specifiers), *optFromClause, valueIdent_));
}
return setLocation(
startLoc,
getPrevTokenEndLoc(),
new (context_)
ESTree::ExportAllDeclarationNode(*optFromClause, valueIdent_));
} else if (checkAndEat(TokenKind::rw_default)) {
// export default
if (check(TokenKind::rw_function) ||
(check(asyncIdent_) && checkAsyncFunction())) {
// export default HoistableDeclaration
// Currently, the only hoistable declarations are functions.
auto optFunDecl = parseFunctionDeclaration(ParamDefault);
if (!optFunDecl) {
return None;
}
return setLocation(
startLoc,
*optFunDecl,
new (context_) ESTree::ExportDefaultDeclarationNode(*optFunDecl));
} else if (check(TokenKind::rw_class)) {
auto optClassDecl = parseClassDeclaration(ParamDefault);
if (!optClassDecl) {
return None;
}
return setLocation(
startLoc,
*optClassDecl,
new (context_) ESTree::ExportDefaultDeclarationNode(*optClassDecl));
#if HERMES_PARSE_FLOW
} else if (context_.getParseFlow() && check(TokenKind::rw_enum)) {
auto optEnum = parseEnumDeclarationFlow();
if (!optEnum) {
return None;
}
return setLocation(
startLoc,
*optEnum,
new (context_) ESTree::ExportDefaultDeclarationNode(*optEnum));
#endif
} else {
// export default AssignmentExpression ;
auto optExpr = parseAssignmentExpression(ParamIn);
if (!optExpr) {
return None;
}
if (!eatSemi()) {
return None;
}
return setLocation(
startLoc,
getPrevTokenEndLoc(),
new (context_) ESTree::ExportDefaultDeclarationNode(*optExpr));
}
} else if (check(TokenKind::l_brace)) {
// export ExportClause FromClause ;
// export ExportClause ;
ESTree::NodeList specifiers{};
llvh::SmallVector<SMRange, 2> invalids{};
auto optExportClause = parseExportClause(specifiers, invalids);
if (!optExportClause) {
return None;
}
ESTree::Node *source = nullptr;
if (check(fromIdent_)) {
// export ExportClause FromClause ;
auto optFromClause = parseFromClause();
if (!optFromClause) {
return None;
}
source = *optFromClause;
} else {
// export ExportClause ;
// ES9.0 15.2.3.1
// When there is no FromClause, any ranges added to invalids are actually
// invalid, and should be reported as errors.
for (const SMRange &range : invalids) {
error(range, "Invalid exported name");
}
}
if (!eatSemi()) {
return None;
}
return setLocation(
startLoc,
getPrevTokenEndLoc(),
new (context_) ESTree::ExportNamedDeclarationNode(
nullptr, std::move(specifiers), source, valueIdent_));
} else if (check(TokenKind::rw_var)) {
// export VariableStatement
auto optVar = parseVariableStatement(Param{});
if (!optVar) {
return None;
}
return setLocation(
startLoc,
*optVar,
new (context_) ESTree::ExportNamedDeclarationNode(
*optVar, {}, nullptr, valueIdent_));
}
// export Declaration [~Yield]
if (!checkDeclaration()) {
error(tok_->getSourceRange(), "expected declaration in export");
return None;
}
auto optDecl = parseDeclaration(Param{});
if (!optDecl) {
return None;
}
ESTree::Node *decl = *optDecl;
UniqueString *kind = valueIdent_;
#if HERMES_PARSE_FLOW
if (isa<ESTree::TypeAliasNode>(decl) || isa<ESTree::OpaqueTypeNode>(decl) ||
isa<ESTree::DeclareTypeAliasNode>(decl) ||
isa<ESTree::InterfaceDeclarationNode>(decl)) {
kind = typeIdent_;
}
#endif
return setLocation(
startLoc,
decl,
new (context_)
ESTree::ExportNamedDeclarationNode(decl, {}, nullptr, kind));
}