in lib/Parser/JSParserImpl.cpp [343:558]
Optional<ESTree::FunctionLikeNode *> JSParserImpl::parseFunctionHelper(
Param param,
bool isDeclaration,
bool forceEagerly) {
// function or async function
assert(check(TokenKind::rw_function) || check(asyncIdent_));
bool isAsync = check(asyncIdent_);
SMLoc startLoc = advance().Start;
if (isAsync) {
// async function
// ^
advance();
}
bool isGenerator = checkAndEat(TokenKind::star);
// newParamYield setting per the grammar:
// FunctionDeclaration: BindingIdentifier[?Yield, ?Await]
// FunctionExpression: BindingIdentifier[~Yield, ~Await]
// GeneratorFunctionDeclaration: BindingIdentifier[?Yield, ?Await]
// GeneratorFunctionExpression: BindingIdentifier[+Yield, ~Await]
// AsyncFunctionDeclaration: BindingIdentifier[?Yield, ?Await]
// AsyncFunctionExpression: BindingIdentifier[+Yield, +Await]
// AsyncGeneratorDeclaration: BindingIdentifier[?Yield, ?Await]
// AsyncGeneratorExpression: BindingIdentifier[+Yield, +Await]
bool nameParamYield = isDeclaration ? paramYield_ : isGenerator;
llvh::SaveAndRestore<bool> saveNameParamYield(paramYield_, nameParamYield);
bool nameParamAwait = isDeclaration ? paramAwait_ : isAsync;
llvh::SaveAndRestore<bool> saveNameParamAwait(paramAwait_, nameParamAwait);
// identifier
auto optId = parseBindingIdentifier(Param{});
// If this is a default function declaration, then we can match
// [+Default] function ( FormalParameters ) { FunctionBody }
// so the identifier is optional and we can make it nullptr.
if (isDeclaration && !param.has(ParamDefault) && !optId) {
errorExpected(
TokenKind::identifier,
"after 'function'",
"location of 'function'",
startLoc);
return None;
}
ESTree::Node *typeParams = nullptr;
#if HERMES_PARSE_FLOW
if (context_.getParseFlow() && check(TokenKind::less)) {
auto optTypeParams = parseTypeParamsFlow();
if (!optTypeParams)
return None;
typeParams = *optTypeParams;
}
#endif
#if HERMES_PARSE_TS
if (context_.getParseTS() && check(TokenKind::less)) {
auto optTypeParams = parseTSTypeParameters();
if (!optTypeParams)
return None;
typeParams = *optTypeParams;
}
#endif
// (
if (!need(
TokenKind::l_paren,
"at start of function parameter list",
isDeclaration ? "function declaration starts here"
: "function expression starts here",
startLoc)) {
return None;
}
ESTree::NodeList paramList;
llvh::SaveAndRestore<bool> saveArgsAndBodyParamYield(
paramYield_, isGenerator);
llvh::SaveAndRestore<bool> saveArgsAndBodyParamAwait(paramAwait_, isAsync);
if (!parseFormalParameters(param, paramList))
return None;
ESTree::Node *returnType = nullptr;
ESTree::Node *predicate = nullptr;
#if HERMES_PARSE_FLOW
if (context_.getParseFlow() && check(TokenKind::colon)) {
SMLoc annotStart = advance(JSLexer::GrammarContext::Type).Start;
if (!check(checksIdent_)) {
auto optRet = parseTypeAnnotationFlow(annotStart);
if (!optRet)
return None;
returnType = *optRet;
}
if (check(checksIdent_)) {
auto optPred = parsePredicateFlow();
if (!optPred)
return None;
predicate = *optPred;
}
}
#endif
#if HERMES_PARSE_TS
if (context_.getParseTS() && check(TokenKind::colon)) {
SMLoc annotStart = advance(JSLexer::GrammarContext::Type).Start;
if (!check(checksIdent_)) {
auto optRet = parseTypeAnnotationTS(annotStart);
if (!optRet)
return None;
returnType = *optRet;
}
}
#endif
// {
if (!need(
TokenKind::l_brace,
isDeclaration ? "in function declaration" : "in function expression",
isDeclaration ? "start of function declaration"
: "start of function expression",
startLoc)) {
return None;
}
SaveStrictModeAndSeenDirectives saveStrictModeAndSeenDirectives{this};
// Grammar context to be used when lexing the closing brace.
auto grammarContext =
isDeclaration ? JSLexer::AllowRegExp : JSLexer::AllowDiv;
if (pass_ == PreParse) {
// Create the nodes we want to keep before the AllocationScope.
ESTree::FunctionLikeNode *node;
if (isDeclaration) {
auto *decl = new (context_) ESTree::FunctionDeclarationNode(
optId ? *optId : nullptr,
std::move(paramList),
nullptr,
typeParams,
returnType,
predicate,
isGenerator,
isAsync);
// Initialize the node with a blank body.
decl->_body = new (context_) ESTree::BlockStatementNode({});
node = decl;
} else {
auto *expr = new (context_) ESTree::FunctionExpressionNode(
optId ? *optId : nullptr,
std::move(paramList),
nullptr,
typeParams,
returnType,
predicate,
isGenerator,
isAsync);
// Initialize the node with a blank body.
expr->_body = new (context_) ESTree::BlockStatementNode({});
node = expr;
}
AllocationScope scope(context_.getAllocator());
auto body = parseFunctionBody(
Param{},
false,
saveArgsAndBodyParamYield.get(),
saveArgsAndBodyParamAwait.get(),
grammarContext,
true);
if (!body)
return None;
return setLocation(startLoc, body.getValue(), node);
}
auto parsedBody = parseFunctionBody(
Param{},
forceEagerly,
saveArgsAndBodyParamYield.get(),
saveArgsAndBodyParamAwait.get(),
grammarContext,
true);
if (!parsedBody)
return None;
auto *body = parsedBody.getValue();
ESTree::FunctionLikeNode *node;
if (isDeclaration) {
auto *decl = new (context_) ESTree::FunctionDeclarationNode(
optId ? *optId : nullptr,
std::move(paramList),
body,
typeParams,
returnType,
predicate,
isGenerator,
isAsync);
node = decl;
} else {
auto *expr = new (context_) ESTree::FunctionExpressionNode(
optId ? *optId : nullptr,
std::move(paramList),
body,
typeParams,
returnType,
predicate,
isGenerator,
isAsync);
node = expr;
}
return setLocation(startLoc, body, node);
}