in lib/Parser/JSParserImpl.cpp [1672:1845]
Optional<ESTree::Node *> JSParserImpl::parseForStatement(Param param) {
assert(check(TokenKind::rw_for));
SMLoc startLoc = advance().Start;
bool await = false;
SMRange awaitRng;
if (paramAwait_ && check(awaitIdent_)) {
awaitRng = advance();
await = true;
}
SMLoc lparenLoc = tok_->getStartLoc();
if (!eat(
TokenKind::l_paren,
JSLexer::AllowRegExp,
"after 'for'",
"location of 'for'",
startLoc))
return None;
ESTree::VariableDeclarationNode *decl = nullptr;
ESTree::NodePtr expr1 = nullptr;
if (checkN(TokenKind::rw_var, TokenKind::rw_const, letIdent_)) {
// Productions valid here:
// for ( var/let/const VariableDeclarationList
// for [await] ( var/let/const VariableDeclaration
SMLoc varStartLoc = tok_->getStartLoc();
auto *declIdent = tok_->getResWordOrIdentifier();
advance();
ESTree::NodeList declList;
if (!parseVariableDeclarationList(Param{}, declList, varStartLoc))
return None;
auto endLoc = declList.back().getEndLoc();
decl = setLocation(
varStartLoc,
endLoc,
new (context_)
ESTree::VariableDeclarationNode(declIdent, std::move(declList)));
} else {
// Productions valid here:
// for [await] ( Expression_opt
// for [await] ( LeftHandSideExpression
if (!check(TokenKind::semi)) {
auto optExpr1 = parseExpression(Param{});
if (!optExpr1)
return None;
expr1 = optExpr1.getValue();
}
}
if (checkN(TokenKind::rw_in, ofIdent_)) {
// Productions valid here:
// for [await] ( var/let/const VariableDeclaration[In] in/of
// for [await] ( LeftHandSideExpression in/of
if (decl && decl->_declarations.size() > 1) {
error(
decl->getSourceRange(),
"Only one binding must be declared in a for-in/for-of loop");
return None;
}
// Check for destructuring pattern on the left and reparse it.
if (expr1 &&
(isa<ESTree::ArrayExpressionNode>(expr1) ||
isa<ESTree::ObjectExpressionNode>(expr1))) {
auto optExpr1 = reparseAssignmentPattern(expr1, false);
if (!optExpr1)
return None;
expr1 = *optExpr1;
}
// Remember whether we are parsing for-in or for-of.
bool const forInLoop = check(TokenKind::rw_in);
advance();
if (forInLoop && await)
error(awaitRng, "unexpected 'await' in for..in loop");
auto optRightExpr =
forInLoop ? parseExpression() : parseAssignmentExpression(ParamIn);
if (!eat(
TokenKind::r_paren,
JSLexer::AllowRegExp,
"after 'for(... in/of ...'",
"location of '('",
lparenLoc))
return None;
auto optBody = parseStatement(param.get(ParamReturn));
if (!optBody || !optRightExpr)
return None;
ESTree::Node *node;
if (forInLoop) {
node = new (context_) ESTree::ForInStatementNode(
decl ? decl : expr1, optRightExpr.getValue(), optBody.getValue());
} else {
node = new (context_) ESTree::ForOfStatementNode(
decl ? decl : expr1,
optRightExpr.getValue(),
optBody.getValue(),
await);
}
return setLocation(startLoc, optBody.getValue(), node);
} else if (checkAndEat(TokenKind::semi)) {
// Productions valid here:
// for ( var/let/const VariableDeclarationList[In] ; Expressionopt ;
// Expressionopt )
// Statement
// for ( Expression[In]opt ; Expressionopt ; Expressionopt ) Statement
if (await)
error(awaitRng, "unexpected 'await' in for loop without 'of'");
if (decl)
ensureDestructuringInitialized(decl);
ESTree::NodePtr test = nullptr;
if (!check(TokenKind::semi)) {
auto optTest = parseExpression();
if (!optTest)
return None;
test = optTest.getValue();
}
if (!eat(
TokenKind::semi,
JSLexer::AllowRegExp,
"after 'for( ... ; ...'",
"location of '('",
lparenLoc))
return None;
ESTree::NodePtr update = nullptr;
if (!check(TokenKind::r_paren)) {
auto optUpdate = parseExpression();
if (!optUpdate)
return None;
update = optUpdate.getValue();
}
if (!eat(
TokenKind::r_paren,
JSLexer::AllowRegExp,
"after 'for( ... ; ... ; ...'",
"location of '('",
lparenLoc))
return None;
auto optBody = parseStatement(param.get(ParamReturn));
if (!optBody)
return None;
return setLocation(
startLoc,
optBody.getValue(),
new (context_) ESTree::ForStatementNode(
decl ? decl : expr1, test, update, optBody.getValue()));
} else {
errorExpected(
TokenKind::semi,
TokenKind::rw_in,
"inside 'for'",
"location of the 'for'",
startLoc);
return None;
}
}