mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
1011 lines
35 KiB
C++
1011 lines
35 KiB
C++
//===--- ParseStmt.cpp - Swift Language Parser for Statements -------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See http://swift.org/LICENSE.txt for license information
|
|
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Statement Parsing and AST Building
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "swift/Parse/Parser.h"
|
|
#include "swift/AST/Attr.h"
|
|
#include "swift/AST/Decl.h"
|
|
#include "swift/Parse/Lexer.h"
|
|
#include "swift/Parse/CodeCompletionCallbacks.h"
|
|
#include "llvm/ADT/PointerUnion.h"
|
|
#include "llvm/ADT/OwningPtr.h"
|
|
#include "llvm/ADT/Twine.h"
|
|
#include "llvm/Support/SaveAndRestore.h"
|
|
|
|
using namespace swift;
|
|
|
|
/// isStartOfStmt - Return true if the specified token starts
|
|
/// a statement.
|
|
///
|
|
bool Parser::isStartOfStmt(const Token &Tok) {
|
|
switch (Tok.getKind()) {
|
|
default: return false;
|
|
case tok::kw_return:
|
|
case tok::kw_if:
|
|
case tok::kw_while:
|
|
case tok::kw_do:
|
|
case tok::kw_for:
|
|
case tok::kw_break:
|
|
case tok::kw_continue:
|
|
case tok::kw_fallthrough:
|
|
case tok::kw_switch:
|
|
case tok::kw_case:
|
|
case tok::kw_default:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/// isStartOfDecl - Return true if this is the start of a decl or decl-import.
|
|
bool Parser::isStartOfDecl(const Token &Tok, const Token &Tok2) {
|
|
switch (Tok.getKind()) {
|
|
case tok::kw_static:
|
|
case tok::kw_extension:
|
|
case tok::kw_var:
|
|
case tok::kw_typealias:
|
|
case tok::kw_union:
|
|
case tok::kw_case:
|
|
case tok::kw_struct:
|
|
case tok::kw_class:
|
|
case tok::kw_import:
|
|
case tok::kw_subscript:
|
|
case tok::kw_constructor:
|
|
case tok::kw_destructor:
|
|
case tok::kw_func:
|
|
return true;
|
|
case tok::kw_protocol:
|
|
return !(Tok2.isAnyOperator() && Tok2.getText().equals("<"));
|
|
default:
|
|
return isStartOfOperatorDecl(Tok, Tok2);
|
|
}
|
|
}
|
|
|
|
ParserStatus Parser::parseExprOrStmt(ExprStmtOrDecl &Result) {
|
|
if (Tok.is(tok::semi)) {
|
|
diagnose(Tok, diag::illegal_semi_stmt)
|
|
.fixItRemove(SourceRange(Tok.getLoc()));
|
|
consumeToken();
|
|
return makeParserError();
|
|
}
|
|
if (isStartOfStmt(Tok)) {
|
|
ParserResult<Stmt> Res = parseStmt();
|
|
if (Res.isNonNull())
|
|
Result = Res.get();
|
|
return Res;
|
|
}
|
|
|
|
if (CodeCompletion)
|
|
CodeCompletion->setExprBeginning(getParserPosition());
|
|
|
|
ParserResult<Expr> ResultExpr = parseExpr(diag::expected_expr,
|
|
/*usesExprBasic*/ false);
|
|
if (ResultExpr.hasCodeCompletion() && CodeCompletion) {
|
|
CodeCompletion->completeExpr();
|
|
return ResultExpr;
|
|
}
|
|
|
|
if (ResultExpr.isNonNull())
|
|
Result = ResultExpr.get();
|
|
|
|
return ResultExpr;
|
|
}
|
|
|
|
static bool isTerminatorForBraceItemListKind(const Token &Tok,
|
|
BraceItemListKind Kind,
|
|
ArrayRef<Parser::ExprStmtOrDecl> ParsedDecls) {
|
|
switch (Kind) {
|
|
case BraceItemListKind::Brace:
|
|
return false;
|
|
case BraceItemListKind::Property:
|
|
return Tok.isContextualKeyword("get") || Tok.isContextualKeyword("set");
|
|
case BraceItemListKind::Case:
|
|
return Tok.is(tok::kw_case) || Tok.is(tok::kw_default);
|
|
case BraceItemListKind::TopLevelCode:
|
|
// When parsing the top level executable code for a module, if we parsed
|
|
// some executable code, then we're done. We want to process (name bind,
|
|
// type check, etc) decls one at a time to make sure that there are not
|
|
// forward type references, etc. There is an outer loop around the parser
|
|
// that will reinvoke the parser at the top level on each statement until
|
|
// EOF. In contrast, it is ok to have forward references between classes,
|
|
// functions, etc.
|
|
for (auto I : ParsedDecls) {
|
|
if (isa<TopLevelCodeDecl>(I.get<Decl*>()))
|
|
// Only bail out if the next token is at the start of a line. If we
|
|
// don't, then we may accidentally allow things like "a = 1 b = 4".
|
|
// FIXME: This is really dubious. This will reject some things, but
|
|
// allow other things we don't want.
|
|
if (Tok.isAtStartOfLine())
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void Parser::consumeTopLevelDecl(ParserPosition BeginParserPosition) {
|
|
backtrackToPosition(BeginParserPosition);
|
|
SourceLoc BeginLoc = Tok.getLoc();
|
|
// Consume tokens up to code completion token.
|
|
while (Tok.isNot(tok::code_complete)) {
|
|
consumeToken();
|
|
}
|
|
// Consume the code completion token, if there is one.
|
|
consumeIf(tok::code_complete);
|
|
// Also perform the same recovery as the main parser to capture tokens from
|
|
// this decl that are past the code completion token.
|
|
skipUntilDeclStmtRBrace();
|
|
SourceLoc EndLoc = Tok.getLoc();
|
|
State->delayDecl(PersistentParserState::DelayedDeclKind::TopLevelCodeDecl, 0,
|
|
CurDeclContext, { BeginLoc, EndLoc },
|
|
BeginParserPosition.PreviousLoc);
|
|
|
|
// Skip the rest of the file to prevent the parser from constructing the AST
|
|
// for it. Forward references are not allowed at the top level.
|
|
skipUntil(tok::eof, /*StopAtCodeComplete=*/false);
|
|
}
|
|
|
|
/// brace-item:
|
|
/// decl
|
|
/// expr
|
|
/// stmt
|
|
/// stmt:
|
|
/// ';'
|
|
/// stmt-assign
|
|
/// stmt-if
|
|
/// stmt-for-c-style
|
|
/// stmt-for-each
|
|
/// stmt-switch
|
|
/// stmt-control-transfer
|
|
/// stmt-control-transfer:
|
|
/// stmt-return
|
|
/// stmt-break
|
|
/// stmt-continue
|
|
/// stmt-fallthrough
|
|
/// stmt-assign:
|
|
/// expr '=' expr
|
|
void Parser::parseBraceItems(SmallVectorImpl<ExprStmtOrDecl> &Entries,
|
|
bool IsTopLevel, BraceItemListKind Kind) {
|
|
// This forms a lexical scope.
|
|
Scope S(this, IsTopLevel ? ScopeKind::TopLevel : ScopeKind::Brace);
|
|
|
|
SmallVector<Decl*, 8> TmpDecls;
|
|
|
|
bool previousHadSemi = true;
|
|
while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof) &&
|
|
Tok.isNot(tok::kw_sil) && Tok.isNot(tok::kw_sil_stage) &&
|
|
!isTerminatorForBraceItemListKind(Tok, Kind, Entries)) {
|
|
bool NeedParseErrorRecovery = false;
|
|
ExprStmtOrDecl Result;
|
|
|
|
// If the previous statement didn't have a semicolon and this new
|
|
// statement doesn't start a line, complain.
|
|
if (!previousHadSemi && !Tok.isAtStartOfLine()) {
|
|
SourceLoc EndOfPreviousLoc = Lexer::getLocForEndOfToken(SourceMgr,
|
|
PreviousLoc);
|
|
diagnose(EndOfPreviousLoc, diag::statement_same_line_without_semi)
|
|
.fixItInsert(EndOfPreviousLoc, ";");
|
|
// FIXME: Add semicolon to the AST?
|
|
}
|
|
|
|
ParserPosition BeginParserPosition;
|
|
if (isCodeCompletionFirstPass())
|
|
BeginParserPosition = getParserPosition();
|
|
|
|
// Parse the decl, stmt, or expression.
|
|
previousHadSemi = false;
|
|
if (isStartOfDecl(Tok, peekToken())) {
|
|
ParserStatus Status =
|
|
parseDecl(TmpDecls, IsTopLevel ? PD_AllowTopLevel : PD_Default);
|
|
if (Status.isError()) {
|
|
NeedParseErrorRecovery = true;
|
|
if (Status.hasCodeCompletion() && IsTopLevel &&
|
|
isCodeCompletionFirstPass()) {
|
|
consumeTopLevelDecl(BeginParserPosition);
|
|
return;
|
|
}
|
|
}
|
|
|
|
for (Decl *D : TmpDecls)
|
|
Entries.push_back(D);
|
|
if (!TmpDecls.empty())
|
|
previousHadSemi = TmpDecls.back()->TrailingSemiLoc.isValid();
|
|
TmpDecls.clear();
|
|
} else if (IsTopLevel && allowTopLevelCode()) {
|
|
// If this is a statement or expression at the top level of the module,
|
|
// Parse it as a child of a TopLevelCodeDecl.
|
|
auto *TLCD = new (Context) TopLevelCodeDecl(CurDeclContext);
|
|
ContextChange CC(*this, TLCD);
|
|
SourceLoc StartLoc = Tok.getLoc();
|
|
|
|
ParserStatus Status = parseExprOrStmt(Result);
|
|
if (Status.hasCodeCompletion() && isCodeCompletionFirstPass()) {
|
|
consumeTopLevelDecl(BeginParserPosition);
|
|
return;
|
|
}
|
|
if (Status.isError()) {
|
|
NeedParseErrorRecovery = true;
|
|
} else {
|
|
auto Brace = BraceStmt::create(Context, StartLoc, Result, Tok.getLoc());
|
|
TLCD->setBody(Brace);
|
|
Entries.push_back(TLCD);
|
|
}
|
|
} else {
|
|
SourceLoc StartLoc = Tok.getLoc();
|
|
if (parseExprOrStmt(Result).isError())
|
|
NeedParseErrorRecovery = true;
|
|
else {
|
|
|
|
// If this is a normal library, you can't have expressions or statements
|
|
// outside at the top level. Diagnose this error.
|
|
if (IsTopLevel) {
|
|
if (!NeedParseErrorRecovery)
|
|
diagnose(StartLoc,
|
|
Result.is<Stmt*>() ? diag::illegal_top_level_stmt :
|
|
diag::illegal_top_level_expr);
|
|
} else {
|
|
Entries.push_back(Result);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!NeedParseErrorRecovery && !previousHadSemi && Tok.is(tok::semi)) {
|
|
if (Result.is<Expr*>()) {
|
|
Result.get<Expr*>()->TrailingSemiLoc = consumeToken(tok::semi);
|
|
} else {
|
|
Result.get<Stmt*>()->TrailingSemiLoc = consumeToken(tok::semi);
|
|
}
|
|
previousHadSemi = true;
|
|
}
|
|
|
|
// If we had a parse error, skip to the start of the next stmt or decl. It
|
|
// would be ideal to stop at the start of the next expression (e.g. "X = 4")
|
|
// but distinguishing the start of an expression from the middle of one is
|
|
// "hard".
|
|
if (NeedParseErrorRecovery) {
|
|
// If there was a parse error and we stopped at the code completion
|
|
// token, then it should have been already handled, so just skip it.
|
|
consumeIf(tok::code_complete);
|
|
skipUntilDeclStmtRBrace();
|
|
|
|
// If we have to recover, pretend that we had a semicolon; it's less
|
|
// noisy that way.
|
|
previousHadSemi = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Parser::parseTopLevelCodeDeclDelayed() {
|
|
auto DelayedState = State->takeDelayedDeclState();
|
|
assert(DelayedState.get() && "should have delayed state");
|
|
|
|
auto BeginParserPosition = getParserPosition(DelayedState->BodyPos);
|
|
auto EndLexerState = L->getStateForEndOfTokenLoc(DelayedState->BodyEnd);
|
|
|
|
// ParserPositionRAII needs a primed parser to restore to.
|
|
if (Tok.is(tok::NUM_TOKENS))
|
|
consumeToken();
|
|
|
|
// Ensure that we restore the parser state at exit.
|
|
ParserPositionRAII PPR(*this);
|
|
|
|
// Create a lexer that can not go past the end state.
|
|
Lexer LocalLex(*L, BeginParserPosition.LS, EndLexerState);
|
|
|
|
// Temporarily swap out the parser's current lexer with our new one.
|
|
llvm::SaveAndRestore<Lexer *> T(L, &LocalLex);
|
|
|
|
// Rewind to the beginning of the top-level code.
|
|
restoreParserPosition(BeginParserPosition);
|
|
|
|
// No need to re-enter the scope: parseBraceItems() will create a scope
|
|
// anyway.
|
|
|
|
// Re-enter the top-level decl context.
|
|
ContextChange CC(*this, DelayedState->ParentContext);
|
|
|
|
SmallVector<ExprStmtOrDecl, 4> Entries;
|
|
parseBraceItems(Entries, true, BraceItemListKind::TopLevelCode);
|
|
}
|
|
|
|
/// Recover from a 'case' or 'default' outside of a 'switch' by consuming up to
|
|
/// the next ':'.
|
|
static ParserResult<Stmt> recoverFromInvalidCase(Parser &P) {
|
|
assert(P.Tok.is(tok::kw_case) || P.Tok.is(tok::kw_default)
|
|
&& "not case or default?!");
|
|
P.diagnose(P.Tok, diag::case_outside_of_switch, P.Tok.getText());
|
|
P.skipUntil(tok::colon);
|
|
// FIXME: Return an ErrorStmt?
|
|
return nullptr;
|
|
}
|
|
|
|
ParserResult<Stmt> Parser::parseStmt() {
|
|
switch (Tok.getKind()) {
|
|
default:
|
|
diagnose(Tok, diag::expected_stmt);
|
|
return nullptr;
|
|
case tok::kw_return: return parseStmtReturn();
|
|
case tok::kw_if: return parseStmtIf();
|
|
case tok::kw_while: return parseStmtWhile();
|
|
case tok::kw_do: return parseStmtDoWhile();
|
|
case tok::kw_for: return parseStmtFor();
|
|
case tok::kw_switch: return parseStmtSwitch();
|
|
/// 'case' and 'default' are only valid at the top level of a switch.
|
|
case tok::kw_case:
|
|
case tok::kw_default: return recoverFromInvalidCase(*this);
|
|
case tok::kw_break:
|
|
return makeParserResult(
|
|
new (Context) BreakStmt(consumeToken(tok::kw_break)));
|
|
case tok::kw_continue:
|
|
return makeParserResult(
|
|
new (Context) ContinueStmt(consumeToken(tok::kw_continue)));
|
|
case tok::kw_fallthrough:
|
|
return makeParserResult(
|
|
new (Context) FallthroughStmt(consumeToken(tok::kw_fallthrough)));
|
|
}
|
|
}
|
|
|
|
/// parseBraceItemList - A brace enclosed expression/statement/decl list. For
|
|
/// example { 1; 4+5; } or { 1; 2 }. Always occurs as part of some other stmt
|
|
/// or decl.
|
|
///
|
|
/// brace-item-list:
|
|
/// '{' brace-item* '}'
|
|
///
|
|
ParserResult<BraceStmt> Parser::parseBraceItemList(Diag<> ID) {
|
|
if (Tok.isNot(tok::l_brace)) {
|
|
diagnose(Tok, ID);
|
|
return nullptr;
|
|
}
|
|
SourceLoc LBLoc = consumeToken(tok::l_brace);
|
|
|
|
SmallVector<ExprStmtOrDecl, 16> Entries;
|
|
SourceLoc RBLoc;
|
|
|
|
parseBraceItems(Entries, false /*NotTopLevel*/);
|
|
if (parseMatchingToken(tok::r_brace, RBLoc,
|
|
diag::expected_rbrace_in_brace_stmt, LBLoc)) {
|
|
// Recover by setting the right brace location to the end location of the
|
|
// last parsed brace item.
|
|
if (Entries.empty())
|
|
RBLoc = LBLoc;
|
|
else {
|
|
if (auto *SubStmt = Entries.back().dyn_cast<Stmt *>())
|
|
RBLoc = SubStmt->getEndLoc();
|
|
else if (auto *SubExpr = Entries.back().dyn_cast<Expr *>())
|
|
RBLoc = SubExpr->getEndLoc();
|
|
else
|
|
RBLoc = Entries.back().get<Decl *>()->getEndLoc();
|
|
}
|
|
}
|
|
|
|
return makeParserResult(BraceStmt::create(Context, LBLoc, Entries, RBLoc));
|
|
}
|
|
|
|
/// parseStmtReturn
|
|
///
|
|
/// stmt-return:
|
|
/// return expr?
|
|
///
|
|
ParserResult<Stmt> Parser::parseStmtReturn() {
|
|
SourceLoc ReturnLoc = consumeToken(tok::kw_return);
|
|
|
|
// Handle the ambiguity between consuming the expression and allowing the
|
|
// enclosing stmt-brace to get it by eagerly eating it unless the return is
|
|
// followed by a '}', ';', or statement keyword.
|
|
if (Tok.isNot(tok::r_brace) && Tok.isNot(tok::semi) && !isStartOfStmt(Tok)) {
|
|
ParserResult<Expr> Result = parseExpr(diag::expected_expr_return);
|
|
return makeParserResult(
|
|
Result, new (Context) ReturnStmt(ReturnLoc, Result.getPtrOrNull()));
|
|
}
|
|
|
|
return makeParserResult(new (Context) ReturnStmt(ReturnLoc, nullptr));
|
|
}
|
|
|
|
|
|
///
|
|
/// stmt-if:
|
|
/// 'if' expr-basic stmt-brace stmt-if-else?
|
|
/// stmt-if-else:
|
|
/// 'else' stmt-brace
|
|
/// 'else' stmt-if
|
|
ParserResult<Stmt> Parser::parseStmtIf() {
|
|
SourceLoc IfLoc = consumeToken(tok::kw_if);
|
|
|
|
ParserStatus Status;
|
|
|
|
ParserResult<Expr> Condition = parseExprBasic(diag::expected_expr_if);
|
|
//Status |= Condition;
|
|
if (Condition.isNull() || Condition.hasCodeCompletion())
|
|
return makeParserResult<Stmt>(Condition, nullptr); // FIXME: better recovery
|
|
|
|
ParserResult<BraceStmt> NormalBody;
|
|
if (auto *CE = dyn_cast<PipeClosureExpr>(Condition.get())) {
|
|
// If we parsed closure after 'if', then it was not the condition, but the
|
|
// 'if' statement body. We can not have a bare closure in an 'if'
|
|
// condition because closures don't conform to LogicValue.
|
|
auto ClosureBody = CE->getBody();
|
|
SourceLoc LBraceLoc = ClosureBody->getStartLoc();
|
|
NormalBody = makeParserErrorResult(ClosureBody);
|
|
Condition = makeParserErrorResult(new (Context) ErrorExpr(LBraceLoc));
|
|
diagnose(IfLoc, diag::missing_condition_after_if)
|
|
.highlight(SourceRange(IfLoc, LBraceLoc));
|
|
}
|
|
if (NormalBody.isNull())
|
|
NormalBody = parseBraceItemList(diag::expected_lbrace_after_if);
|
|
if (NormalBody.isNull())
|
|
return nullptr; // FIXME: better recovery
|
|
|
|
Status |= NormalBody;
|
|
|
|
SourceLoc ElseLoc;
|
|
ParserResult<Stmt> ElseBody;
|
|
if (Tok.is(tok::kw_else)) {
|
|
ElseLoc = consumeToken(tok::kw_else);
|
|
if (Tok.is(tok::kw_if))
|
|
ElseBody = parseStmtIf();
|
|
else
|
|
ElseBody = parseBraceItemList(diag::expected_lbrace_after_else);
|
|
Status |= ElseBody;
|
|
}
|
|
|
|
return makeParserResult(
|
|
Status, new (Context) IfStmt(IfLoc, Condition.get(), NormalBody.get(),
|
|
ElseLoc, ElseBody.getPtrOrNull()));
|
|
}
|
|
|
|
///
|
|
/// stmt-while:
|
|
/// 'while' expr-basic stmt-brace
|
|
ParserResult<Stmt> Parser::parseStmtWhile() {
|
|
SourceLoc WhileLoc = consumeToken(tok::kw_while);
|
|
|
|
ParserStatus Status;
|
|
|
|
ParserResult<Expr> Condition = parseExprBasic(diag::expected_expr_while);
|
|
Status |= Condition;
|
|
if (Condition.isNull() || Condition.hasCodeCompletion())
|
|
return makeParserResult<Stmt>(Status, nullptr); // FIXME: better recovery
|
|
|
|
ParserResult<BraceStmt> Body;
|
|
if (auto *CE = dyn_cast<PipeClosureExpr>(Condition.get())) {
|
|
// If we parsed a closure after 'while', then it was not the condition, but
|
|
// the 'while' statement body. We can not have a bare closure in a 'while'
|
|
// condition because closures don't conform to LogicValue.
|
|
auto ClosureBody = CE->getBody();
|
|
SourceLoc LBraceLoc = ClosureBody->getStartLoc();
|
|
Body = makeParserErrorResult(ClosureBody);
|
|
Condition = makeParserErrorResult(new (Context) ErrorExpr(LBraceLoc));
|
|
diagnose(WhileLoc, diag::missing_condition_after_while)
|
|
.highlight(SourceRange(WhileLoc, LBraceLoc));
|
|
}
|
|
if (Body.isNull())
|
|
Body = parseBraceItemList(diag::expected_lbrace_after_while);
|
|
if (Body.isNull())
|
|
return nullptr; // FIXME: better recovery
|
|
|
|
Status |= Body;
|
|
|
|
return makeParserResult(
|
|
Status, new (Context) WhileStmt(WhileLoc, Condition.get(), Body.get()));
|
|
}
|
|
|
|
///
|
|
/// stmt-do-while:
|
|
/// 'do' stmt-brace 'while' expr
|
|
ParserResult<Stmt> Parser::parseStmtDoWhile() {
|
|
SourceLoc DoLoc = consumeToken(tok::kw_do);
|
|
|
|
ParserResult<BraceStmt> Body =
|
|
parseBraceItemList(diag::expected_lbrace_after_do);
|
|
if (Body.isNull())
|
|
return nullptr; // FIXME: better recovery
|
|
|
|
SourceLoc WhileLoc;
|
|
if (parseToken(tok::kw_while, WhileLoc, diag::expected_while_in_dowhile))
|
|
return nullptr; // FIXME: better recovery
|
|
|
|
ParserPosition ConditionStartState;
|
|
if (Tok.is(tok::l_brace)) {
|
|
// It is unusual for the condition expression to start with a left brace,
|
|
// and we anticipate the need to do recovery. Save the parser state so
|
|
// that we can rewind.
|
|
ConditionStartState = getParserPosition();
|
|
}
|
|
|
|
ParserResult<Expr> Condition = parseExpr(diag::expected_expr_do_while);
|
|
if (Condition.isNull() || Condition.hasCodeCompletion())
|
|
return makeParserResult<Stmt>(Condition, nullptr); // FIXME: better recovery
|
|
|
|
if (auto *CE = dyn_cast<PipeClosureExpr>(Condition.get())) {
|
|
// If we parsed a closure after 'do ... while', then it was not the
|
|
// condition, but a beginning of the next statement. We can not have a
|
|
// bare closure in a 'do ... while' condition because closures don't
|
|
// conform to LogicValue.
|
|
SourceLoc LBraceLoc = CE->getBody()->getStartLoc();
|
|
Condition = makeParserErrorResult(new (Context) ErrorExpr(LBraceLoc));
|
|
diagnose(WhileLoc, diag::missing_condition_after_while);
|
|
|
|
// We did not actually want to parse the next statement.
|
|
backtrackToPosition(ConditionStartState);
|
|
}
|
|
|
|
return makeParserResult(
|
|
new (Context) DoWhileStmt(DoLoc, Condition.get(), WhileLoc, Body.get()));
|
|
}
|
|
|
|
ParserResult<Stmt> Parser::parseStmtFor() {
|
|
SourceLoc ForLoc = consumeToken(tok::kw_for);
|
|
|
|
// The c-style-for loop and foreach-style-for loop are conflated together into
|
|
// a single keyword, so we have to do some lookahead to resolve what is going
|
|
// on.
|
|
|
|
if (Tok.is(tok::l_paren)) {
|
|
auto SavedPosition = getParserPosition();
|
|
consumeToken(tok::l_paren);
|
|
skipUntil(tok::r_paren);
|
|
bool IsCStyle = peekToken().is(tok::l_brace);
|
|
backtrackToPosition(SavedPosition);
|
|
if (IsCStyle)
|
|
return parseStmtForCStyle(ForLoc);
|
|
return parseStmtForEach(ForLoc);
|
|
}
|
|
|
|
// If we have a leading identifier followed by a ':' or 'in', then this is a
|
|
// pattern, so it is foreach.
|
|
//
|
|
// For error recovery, also parse "for in ..." as foreach.
|
|
if ((isStartOfBindingName(Tok) &&
|
|
(peekToken().is(tok::colon) || peekToken().is(tok::kw_in))) ||
|
|
Tok.is(tok::kw_in))
|
|
return parseStmtForEach(ForLoc);
|
|
|
|
// Otherwise, this is some sort of c-style for loop.
|
|
return parseStmtForCStyle(ForLoc);
|
|
}
|
|
|
|
/// stmt-for-c-style:
|
|
/// 'for' stmt-for-c-style-init? ';' expr? ';' expr-or-stmt-assign-basic?
|
|
/// stmt-brace
|
|
/// 'for' '(' stmt-for-c-style-init? ';' expr? ';'
|
|
/// expr-or-stmt-assign-basic? ')' stmt-brace
|
|
/// stmt-for-c-style-init:
|
|
/// decl-var
|
|
/// expr-basic-or-stmt-assign
|
|
ParserResult<Stmt> Parser::parseStmtForCStyle(SourceLoc ForLoc) {
|
|
SourceLoc Semi1Loc, Semi2Loc;
|
|
SourceLoc LPLoc, RPLoc;
|
|
bool LPLocConsumed = false;
|
|
|
|
ParserStatus Status;
|
|
|
|
bool HaveFirst = false;
|
|
ParserResult<Expr> First;
|
|
SmallVector<Decl*, 2> FirstDecls;
|
|
ParserResult<Expr> Second;
|
|
ParserResult<Expr> Third;
|
|
ParserResult<BraceStmt> Body;
|
|
|
|
// Introduce a new scope to contain any var decls in the init value.
|
|
Scope S(this, ScopeKind::ForVars);
|
|
|
|
if (Tok.is(tok::l_paren)) {
|
|
LPLoc = consumeToken();
|
|
LPLocConsumed = true;
|
|
}
|
|
// Parse the first part, either a var, expr, or stmt-assign.
|
|
if (Tok.is(tok::kw_var)) {
|
|
ParserStatus VarDeclStatus = parseDeclVar(false, FirstDecls);
|
|
if (VarDeclStatus.isError())
|
|
return VarDeclStatus; // FIXME: better recovery
|
|
} else if (Tok.isNot(tok::semi)) {
|
|
HaveFirst = true;
|
|
First = parseExpr(diag::expected_expr);
|
|
Status |= First;
|
|
if (First.isNull() || First.hasCodeCompletion())
|
|
return makeParserResult<Stmt>(Status, nullptr); // FIXME: better recovery
|
|
}
|
|
|
|
ArrayRef<Decl *> FirstDeclsContext;
|
|
if (!FirstDecls.empty())
|
|
FirstDeclsContext = Context.AllocateCopy(FirstDecls);
|
|
|
|
if (Tok.isNot(tok::semi)) {
|
|
if (auto *CE = dyn_cast_or_null<PipeClosureExpr>(First.getPtrOrNull())) {
|
|
// We have seen:
|
|
// for { ... }
|
|
// and there's no semicolon after that.
|
|
//
|
|
// We parsed the brace statement as a closure. Recover by using the
|
|
// brace statement as a 'for' body.
|
|
auto ClosureBody = CE->getBody();
|
|
SourceLoc LBraceLoc = ClosureBody->getStartLoc();
|
|
First = makeParserErrorResult(new (Context) ErrorExpr(LBraceLoc));
|
|
Second = nullptr;
|
|
Third = nullptr;
|
|
Body = makeParserErrorResult(ClosureBody);
|
|
diagnose(ForLoc, diag::missing_init_for_stmt)
|
|
.highlight(SourceRange(ForLoc, LBraceLoc));
|
|
Status.setIsParseError();
|
|
|
|
return makeParserResult(
|
|
Status, new (Context) ForStmt(ForLoc, First.getPtrOrNull(),
|
|
FirstDeclsContext,
|
|
Semi1Loc, Second.getPtrOrNull(),
|
|
Semi2Loc, Third.getPtrOrNull(),
|
|
Body.get()));
|
|
}
|
|
}
|
|
|
|
// Consume the first semicolon.
|
|
if (parseToken(tok::semi, Semi1Loc, diag::expected_semi_for_stmt))
|
|
return nullptr; // FIXME: better recovery
|
|
|
|
if (Tok.isNot(tok::semi)) {
|
|
Second = parseExpr(diag::expected_cond_for_stmt);
|
|
Status |= Second;
|
|
if (Second.isNull() || Second.hasCodeCompletion())
|
|
return makeParserResult<Stmt>(Status, nullptr); // FIXME: better recovery
|
|
}
|
|
|
|
if (Tok.isNot(tok::semi)) {
|
|
Expr *RecoveredCondition = nullptr;
|
|
BraceStmt *RecoveredBody = nullptr;
|
|
if (auto *CE = dyn_cast<PipeClosureExpr>(Second.get())) {
|
|
// We have seen:
|
|
// for ... ; { ... }
|
|
// and there's no semicolon after that.
|
|
//
|
|
// We parsed the brace statement as a closure. Recover by using the
|
|
// brace statement as a 'for' body.
|
|
RecoveredCondition = nullptr;
|
|
RecoveredBody = CE->getBody();
|
|
}
|
|
if (auto *CE = dyn_cast<CallExpr>(Second.get())) {
|
|
if (auto *PE = dyn_cast<ParenExpr>(CE->getArg())) {
|
|
if (PE->hasTrailingClosure()) {
|
|
// We have seen:
|
|
// for ... ; ... { ... }
|
|
// and there's no semicolon after that.
|
|
//
|
|
// We parsed the condition as a CallExpr with a brace statement as a
|
|
// trailing closure. Recover by using the original expression as the
|
|
// condition and brace statement as a 'for' body.
|
|
RecoveredBody = cast<PipeClosureExpr>(PE->getSubExpr())->getBody();
|
|
RecoveredCondition = CE->getFn();
|
|
}
|
|
}
|
|
}
|
|
if (RecoveredBody) {
|
|
SourceLoc LBraceLoc = RecoveredBody->getStartLoc();
|
|
Second = makeParserErrorResult(RecoveredCondition);
|
|
Third = nullptr;
|
|
Body = makeParserErrorResult(RecoveredBody);
|
|
diagnose(LBraceLoc, diag::expected_semi_for_stmt)
|
|
.highlight(SourceRange(ForLoc, LBraceLoc));
|
|
Status.setIsParseError();
|
|
|
|
return makeParserResult(
|
|
Status, new (Context) ForStmt(ForLoc, First.getPtrOrNull(),
|
|
FirstDeclsContext,
|
|
Semi1Loc, Second.getPtrOrNull(),
|
|
Semi2Loc, Third.getPtrOrNull(),
|
|
Body.get()));
|
|
}
|
|
}
|
|
|
|
// Consume the second semicolon.
|
|
if (parseToken(tok::semi, Semi2Loc, diag::expected_semi_for_stmt))
|
|
return nullptr; // FIXME: better recovery
|
|
|
|
if (Tok.isNot(tok::l_brace)) {
|
|
Third = parseExpr(diag::expected_expr, /*isExprBasic=*/true);
|
|
Status |= Third;
|
|
if (Third.isNull() || Third.hasCodeCompletion())
|
|
return makeParserResult<Stmt>(Status, nullptr); // FIXME: better recovery
|
|
}
|
|
|
|
if (LPLocConsumed && parseMatchingToken(tok::r_paren, RPLoc,
|
|
diag::expected_rparen_for_stmt,LPLoc))
|
|
return nullptr; // FIXME: better recovery
|
|
|
|
if ((Body = parseBraceItemList(diag::expected_lbrace_after_for)).isNull())
|
|
return nullptr; // FIXME: better recovery
|
|
|
|
return makeParserResult(
|
|
new (Context) ForStmt(ForLoc, First.getPtrOrNull(), FirstDeclsContext,
|
|
Semi1Loc, Second.getPtrOrNull(),
|
|
Semi2Loc, Third.getPtrOrNull(), Body.get()));
|
|
}
|
|
|
|
///
|
|
/// stmt-for-each:
|
|
/// 'for' pattern 'in' expr-basic stmt-brace
|
|
ParserResult<Stmt> Parser::parseStmtForEach(SourceLoc ForLoc) {
|
|
ParserResult<Pattern> Pattern = parsePattern();
|
|
if (Pattern.isNull())
|
|
// Recover by creating a "_" pattern.
|
|
Pattern = makeParserErrorResult(new (Context) AnyPattern(SourceLoc()));
|
|
|
|
SourceLoc InLoc;
|
|
parseToken(tok::kw_in, InLoc, diag::expected_foreach_in);
|
|
|
|
ParserPosition ContainerStartState;
|
|
if (Tok.is(tok::l_brace)) {
|
|
// It is unusual for the container expression to start with a left brace,
|
|
// and we anticipate the need to do recovery. Save the parser state so
|
|
// that we can rewind.
|
|
ContainerStartState = getParserPosition();
|
|
}
|
|
|
|
ParserResult<Expr> Container =
|
|
parseExprBasic(diag::expected_foreach_container);
|
|
if (Container.hasCodeCompletion())
|
|
return makeParserCodeCompletionResult<Stmt>();
|
|
if (Container.isNull())
|
|
Container =
|
|
makeParserErrorResult(new (Context) ErrorExpr(Tok.getLoc()));
|
|
|
|
if (auto *CE = dyn_cast<PipeClosureExpr>(Container.get())) {
|
|
diagnose(CE->getStartLoc(), diag::expected_foreach_container);
|
|
|
|
// If the container expression turns out to be a closure, then it was not
|
|
// the container expression, but the 'for' statement body. We can not have
|
|
// a bare closure as a container expression because closures don't conform
|
|
// to Enumerable.
|
|
Container =
|
|
makeParserErrorResult(new (Context) ErrorExpr(CE->getStartLoc()));
|
|
|
|
// Backtrack to the '{' so that we can re-parse the body in the correct
|
|
// lexical scope.
|
|
backtrackToPosition(ContainerStartState);
|
|
}
|
|
|
|
// Introduce a new scope and place the variables in the pattern into that
|
|
// scope.
|
|
// FIXME: We may want to merge this scope with the scope introduced by
|
|
// the stmt-brace, as in C++.
|
|
Scope S(this, ScopeKind::ForeachVars);
|
|
SmallVector<Decl *, 2> Decls;
|
|
DeclAttributes Attributes;
|
|
addVarsToScope(Pattern.get(), Decls, Attributes);
|
|
|
|
// stmt-brace
|
|
ParserResult<BraceStmt> Body =
|
|
parseBraceItemList(diag::expected_foreach_lbrace);
|
|
|
|
if (Body.isNull())
|
|
return nullptr; // FIXME: better recovery
|
|
|
|
return makeParserResult(
|
|
new (Context) ForEachStmt(ForLoc, Pattern.get(), InLoc,
|
|
Container.get(), Body.get()));
|
|
}
|
|
|
|
///
|
|
/// stmt-switch:
|
|
/// 'switch' expr-basic '{' stmt-case* '}'
|
|
ParserResult<Stmt> Parser::parseStmtSwitch() {
|
|
SourceLoc SwitchLoc = consumeToken(tok::kw_switch);
|
|
|
|
bool SubjectStartsWithLBrace = Tok.is(tok::l_brace);
|
|
ParserPosition SubjectStartState;
|
|
if (SubjectStartsWithLBrace) {
|
|
// It is unusual for the subject expression to start with a left brace, and
|
|
// we anticipate the need to do recovery. Save the parser state so that we
|
|
// can rewind.
|
|
SubjectStartState = getParserPosition();
|
|
}
|
|
|
|
ParserResult<Expr> SubjectExpr = parseExprBasic(diag::expected_switch_expr);
|
|
if (SubjectExpr.hasCodeCompletion())
|
|
return makeParserCodeCompletionResult<Stmt>();
|
|
|
|
if (!Tok.is(tok::l_brace)) {
|
|
if (!SubjectStartsWithLBrace) {
|
|
diagnose(Tok, diag::expected_lbrace_after_switch);
|
|
return nullptr;
|
|
}
|
|
|
|
diagnose(SwitchLoc, diag::expected_switch_expr);
|
|
|
|
// We are going to reparse what we parsed as subject expr.
|
|
SubjectExpr = nullptr;
|
|
|
|
// Backtrack to the '{' so that we can re-parse the switch body correctly.
|
|
//
|
|
// FIXME: Even though we are going to re-parse the body, we have already
|
|
// emitted errors about 'case' outside of switch, when we were parsing this
|
|
// as a subject expr.
|
|
backtrackToPosition(SubjectStartState);
|
|
}
|
|
|
|
if (SubjectExpr.isNull())
|
|
SubjectExpr = makeParserErrorResult(new (Context) ErrorExpr(Tok.getLoc()));
|
|
|
|
SourceLoc lBraceLoc = consumeToken(tok::l_brace);
|
|
SourceLoc rBraceLoc;
|
|
|
|
ParserStatus Status;
|
|
|
|
// If there are non-case-label statements at the start of the switch body,
|
|
// raise an error and recover by parsing and discarding them.
|
|
bool DiagnosedNotCoveredStmt = false;
|
|
while (!Tok.is(tok::kw_case) && !Tok.is(tok::kw_default)
|
|
&& !Tok.is(tok::r_brace) && !Tok.is(tok::eof)) {
|
|
if (!DiagnosedNotCoveredStmt) {
|
|
diagnose(Tok, diag::stmt_in_switch_not_covered_by_case);
|
|
DiagnosedNotCoveredStmt = true;
|
|
}
|
|
ExprStmtOrDecl NotCoveredStmt;
|
|
Status |= parseExprOrStmt(NotCoveredStmt);
|
|
}
|
|
|
|
SmallVector<CaseStmt*, 8> cases;
|
|
bool parsedDefault = false;
|
|
bool parsedBlockAfterDefault = false;
|
|
while (Tok.is(tok::kw_case) || Tok.is(tok::kw_default)) {
|
|
// We cannot have additional cases after a default clause. Complain on
|
|
// the first offender.
|
|
if (parsedDefault && !parsedBlockAfterDefault) {
|
|
parsedBlockAfterDefault = true;
|
|
diagnose(Tok, diag::case_after_default);
|
|
}
|
|
|
|
ParserResult<CaseStmt> Case = parseStmtCase();
|
|
Status |= Case;
|
|
if (Case.isNonNull()) {
|
|
cases.push_back(Case.get());
|
|
if (Case.get()->isDefault())
|
|
parsedDefault = true;
|
|
}
|
|
}
|
|
|
|
if (parseMatchingToken(tok::r_brace, rBraceLoc,
|
|
diag::expected_rbrace_switch, lBraceLoc)) {
|
|
Status.setIsParseError();
|
|
}
|
|
|
|
return makeParserResult(
|
|
Status, SwitchStmt::create(SwitchLoc, SubjectExpr.get(), lBraceLoc,
|
|
cases, rBraceLoc, Context));
|
|
}
|
|
|
|
ParserStatus Parser::parseStmtCaseLabels(SmallVectorImpl<CaseLabel *> &labels,
|
|
SmallVectorImpl<Decl *> &boundDecls) {
|
|
// We must have at least one case label.
|
|
assert(Tok.is(tok::kw_case) || Tok.is(tok::kw_default));
|
|
|
|
ParserStatus Status;
|
|
|
|
bool parsedDefault = false;
|
|
bool parsedOtherLabelWithDefault = false;
|
|
do {
|
|
// 'default' should label a block by itself.
|
|
if (parsedDefault && !parsedOtherLabelWithDefault) {
|
|
diagnose(Tok, diag::default_with_other_labels);
|
|
parsedOtherLabelWithDefault = true;
|
|
}
|
|
|
|
// case-label ::= 'case' matching-pattern (',' matching-pattern)*
|
|
// ('where' expr)? ':'
|
|
if (Tok.is(tok::kw_case)) {
|
|
SourceLoc caseLoc = consumeToken();
|
|
|
|
// Parse comma-separated patterns.
|
|
SmallVector<Pattern *, 2> patterns;
|
|
do {
|
|
ParserResult<Pattern> pattern = parseMatchingPattern();
|
|
Status |= pattern;
|
|
if (pattern.isNonNull()) {
|
|
// Add variable bindings from the pattern to the case scope.
|
|
DeclAttributes defaultAttributes;
|
|
addVarsToScope(pattern.get(), boundDecls, defaultAttributes);
|
|
patterns.push_back(pattern.get());
|
|
}
|
|
} while (consumeIf(tok::comma));
|
|
|
|
// Parse an optional 'where' guard.
|
|
SourceLoc whereLoc;
|
|
Expr *guardExpr = nullptr;
|
|
|
|
if (Tok.is(tok::kw_where)) {
|
|
whereLoc = consumeToken();
|
|
ParserResult<Expr> guard = parseExpr(diag::expected_case_where_expr);
|
|
Status |= guard;
|
|
if (guard.isNonNull())
|
|
guardExpr = guard.get();
|
|
}
|
|
|
|
SourceLoc colonLoc = Tok.getLoc();
|
|
if (!Tok.is(tok::colon))
|
|
diagnose(Tok, diag::expected_case_colon, "case");
|
|
else
|
|
colonLoc = consumeToken();
|
|
|
|
auto label = CaseLabel::create(Context, /*isDefault*/false,
|
|
caseLoc, patterns, whereLoc, guardExpr,
|
|
colonLoc);
|
|
labels.push_back(label);
|
|
continue;
|
|
}
|
|
|
|
// case-label ::= 'default' ':'
|
|
|
|
// 'default' should label a block by itself.
|
|
if (!labels.empty() && !parsedOtherLabelWithDefault) {
|
|
diagnose(Tok, diag::default_with_other_labels);
|
|
parsedOtherLabelWithDefault = true;
|
|
}
|
|
|
|
parsedDefault = true;
|
|
SourceLoc defaultLoc = consumeToken(tok::kw_default);
|
|
|
|
// We don't allow 'where' guards on a 'default' block. For recovery
|
|
// parse one if present.
|
|
SourceLoc whereLoc;
|
|
Expr *guardExpr = nullptr;
|
|
if (Tok.is(tok::kw_where)) {
|
|
diagnose(Tok, diag::default_with_where);
|
|
whereLoc = consumeToken();
|
|
ParserResult<Expr> guard = parseExpr(diag::expected_case_where_expr);
|
|
Status |= guard;
|
|
if (guard.isNonNull())
|
|
guardExpr = guard.get();
|
|
}
|
|
|
|
SourceLoc colonLoc = Tok.getLoc();
|
|
if (!Tok.is(tok::colon))
|
|
diagnose(Tok, diag::expected_case_colon, "default");
|
|
colonLoc = consumeToken();
|
|
|
|
// Create an implicit AnyPattern to represent the default match.
|
|
auto any = new (Context) AnyPattern(defaultLoc);
|
|
auto label = CaseLabel::create(Context, /*isDefault*/true,
|
|
defaultLoc, any, whereLoc, guardExpr,
|
|
colonLoc);
|
|
labels.push_back(label);
|
|
} while (Tok.is(tok::kw_case) || Tok.is(tok::kw_default));
|
|
return Status;
|
|
}
|
|
|
|
// stmt-case ::= case-label+ brace-item*
|
|
ParserResult<CaseStmt> Parser::parseStmtCase() {
|
|
// A case block has its own scope for variables bound out of the pattern.
|
|
Scope scope(this, ScopeKind::CaseVars);
|
|
|
|
ParserStatus Status;
|
|
|
|
SmallVector<CaseLabel*, 2> labels;
|
|
SmallVector<Decl*, 4> boundDecls;
|
|
Status |= parseStmtCaseLabels(labels, boundDecls);
|
|
|
|
assert(!labels.empty() && "did not parse any labels?!");
|
|
|
|
// Case blocks with multiple patterns cannot bind variables.
|
|
if (!boundDecls.empty()
|
|
&& (labels.size() > 1 || labels[0]->getPatterns().size() > 1))
|
|
diagnose(boundDecls[0]->getLoc(),
|
|
diag::var_binding_with_multiple_case_patterns);
|
|
|
|
SmallVector<ExprStmtOrDecl, 8> bodyItems;
|
|
|
|
SourceLoc startOfBody = Tok.getLoc();
|
|
parseBraceItems(bodyItems, /*isTopLevel*/ false, BraceItemListKind::Case);
|
|
BraceStmt *body = BraceStmt::create(Context,
|
|
startOfBody, bodyItems, Tok.getLoc());
|
|
|
|
return makeParserResult(
|
|
Status, CaseStmt::create(Context, labels, !boundDecls.empty(), body));
|
|
}
|