blob: 89b272cf1b3c49d25572c3f3ebcc9ccbd97479ed [file] [log] [blame]
//===--- StmtSyntax.cpp - Swift Statement Syntax Implementation -----------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#include "swift/Syntax/TokenSyntax.h"
#include "swift/Syntax/ExprSyntax.h"
#include "swift/Syntax/StmtSyntax.h"
using namespace swift;
using namespace swift::syntax;
#pragma mark - statement API
StmtSyntax::StmtSyntax(const RC<SyntaxData> Root, const StmtSyntaxData *Data)
: Syntax(Root, Data) {}
#pragma mark - unknown-statement Data
UnknownStmtSyntaxData::UnknownStmtSyntaxData(RC<RawSyntax> Raw,
const SyntaxData *Parent,
CursorIndex IndexInParent)
: UnknownSyntaxData(Raw, Parent, IndexInParent) {
assert(Raw->Kind == SyntaxKind::UnknownStmt);
}
RC<UnknownStmtSyntaxData>
UnknownStmtSyntaxData::make(RC<RawSyntax> Raw,
const SyntaxData *Parent,
CursorIndex IndexInParent) {
auto UnknownRaw = RawSyntax::make(SyntaxKind::UnknownStmt, Raw->Layout,
Raw->Presence);
return RC<UnknownStmtSyntaxData> {
new UnknownStmtSyntaxData {
UnknownRaw, Parent, IndexInParent
}
};
}
#pragma mark - unknown-statement API
UnknownStmtSyntax::UnknownStmtSyntax(const RC<SyntaxData> Root,
const UnknownStmtSyntaxData *Data)
: UnknownSyntax(Root, Data) {}
#pragma mark fallthrough-statement Data
FallthroughStmtSyntaxData::FallthroughStmtSyntaxData(RC<RawSyntax> Raw,
const SyntaxData *Parent,
CursorIndex IndexInParent)
: StmtSyntaxData(Raw, Parent, IndexInParent) {
assert(Raw->Kind == SyntaxKind::FallthroughStmt);
assert(Raw->Layout.size() == 1);
syntax_assert_child_token_text(Raw,
FallthroughStmtSyntax::Cursor::FallthroughKeyword,
tok::kw_fallthrough, "fallthrough");
}
RC<FallthroughStmtSyntaxData>
FallthroughStmtSyntaxData::make(RC<RawSyntax> Raw,
const SyntaxData *Parent,
CursorIndex IndexInParent) {
return RC<FallthroughStmtSyntaxData> {
new FallthroughStmtSyntaxData { Raw, Parent, IndexInParent }
};
}
RC<FallthroughStmtSyntaxData> FallthroughStmtSyntaxData::makeBlank() {
return make(RawSyntax::make(SyntaxKind::FallthroughStmt,
{
TokenSyntax::missingToken(tok::kw_fallthrough, "fallthrough"),
},
SourcePresence::Present));
}
#pragma mark fallthrough-statement API
FallthroughStmtSyntax::
FallthroughStmtSyntax(const RC<SyntaxData> Root,
const FallthroughStmtSyntaxData *Data)
: StmtSyntax(Root, Data) {}
FallthroughStmtSyntax
FallthroughStmtSyntax::make(RC<RawSyntax> Raw, const SyntaxData *Parent,
CursorIndex IndexInParent) {
assert(Raw->Layout.size() == 1);
syntax_assert_child_token_text(Raw,
Cursor::FallthroughKeyword,
tok::kw_fallthrough, "fallthrough");
auto Data = FallthroughStmtSyntaxData::make(Raw, Parent, IndexInParent);
return FallthroughStmtSyntax {
Data, Data.get(),
};
}
RC<TokenSyntax> FallthroughStmtSyntax::getFallthroughKeyword() const {
return cast<TokenSyntax>(getRaw()->getChild(Cursor::FallthroughKeyword));
}
FallthroughStmtSyntax FallthroughStmtSyntax::
withFallthroughKeyword(RC<TokenSyntax> NewFallthroughKeyword) const {
syntax_assert_token_is(NewFallthroughKeyword, tok::kw_fallthrough,
"fallthrough");
return Data->replaceChild<FallthroughStmtSyntax>(NewFallthroughKeyword,
Cursor::FallthroughKeyword);
}
CodeBlockStmtSyntaxData::CodeBlockStmtSyntaxData(RC<RawSyntax> Raw,
const SyntaxData *Parent,
CursorIndex IndexInParent)
: StmtSyntaxData(Raw, Parent, IndexInParent) {
assert(Raw->Kind == SyntaxKind::CodeBlockStmt);
syntax_assert_child_token_text(Raw, CodeBlockStmtSyntax::Cursor::LeftBrace,
tok::l_brace, "{");
syntax_assert_child_kind(Raw, CodeBlockStmtSyntax::Cursor::Elements,
SyntaxKind::StmtList);
syntax_assert_child_token_text(Raw, CodeBlockStmtSyntax::Cursor::RightBrace,
tok::r_brace, "}");
}
RC<CodeBlockStmtSyntaxData>
CodeBlockStmtSyntaxData::make(RC<RawSyntax> Raw, const SyntaxData *Parent,
CursorIndex IndexInParent) {
return RC<CodeBlockStmtSyntaxData> {
new CodeBlockStmtSyntaxData { Raw, Parent, IndexInParent }
};
}
RC<CodeBlockStmtSyntaxData>
CodeBlockStmtSyntaxData::makeBlank() {
return make(RawSyntax::make(SyntaxKind::CodeBlockStmt,
{
TokenSyntax::missingToken(tok::l_brace, "{"),
RawSyntax::missing(SyntaxKind::StmtList),
TokenSyntax::missingToken(tok::r_brace, "}"),
},
SourcePresence::Present));
}
#pragma mark - break-statement Data
BreakStmtSyntaxData::BreakStmtSyntaxData(RC<RawSyntax> Raw,
const SyntaxData *Parent,
CursorIndex IndexInParent)
: StmtSyntaxData(Raw, Parent, IndexInParent) {
assert(Raw->Layout.size() == 2);
syntax_assert_child_token_text(Raw, BreakStmtSyntax::Cursor::BreakKeyword,
tok::kw_break, "break");
syntax_assert_child_token(Raw, BreakStmtSyntax::Cursor::Label,
tok::identifier);
}
RC<BreakStmtSyntaxData>
BreakStmtSyntaxData::make(RC<RawSyntax> Raw, const SyntaxData *Parent,
CursorIndex IndexInParent) {
return RC<BreakStmtSyntaxData> {
new BreakStmtSyntaxData {
Raw, Parent, IndexInParent
}
};
}
RC<BreakStmtSyntaxData> BreakStmtSyntaxData::makeBlank() {
return make(RawSyntax::make(SyntaxKind::BreakStmt,
{
TokenSyntax::missingToken(tok::kw_break,
"break"),
TokenSyntax::missingToken(tok::identifier, ""),
},
SourcePresence::Present));
}
#pragma mark - break-statement API
BreakStmtSyntax::BreakStmtSyntax(const RC<SyntaxData> Root,
BreakStmtSyntaxData *Data)
: StmtSyntax(Root, Data) {}
BreakStmtSyntax BreakStmtSyntax::make(RC<RawSyntax> Raw,
const SyntaxData *Parent,
CursorIndex IndexInParent) {
auto Data = BreakStmtSyntaxData::make(Raw, Parent, IndexInParent);
return { Data, Data.get() };
}
BreakStmtSyntax BreakStmtSyntax::makeBlank() {
auto Data = BreakStmtSyntaxData::makeBlank();
return { Data, Data.get() };
}
RC<TokenSyntax> BreakStmtSyntax::getBreakKeyword() const {
return cast<TokenSyntax>(getRaw()->getChild(Cursor::BreakKeyword));
}
BreakStmtSyntax
BreakStmtSyntax::withBreakKeyword(RC<TokenSyntax> NewBreakKeyword) const {
syntax_assert_token_is(NewBreakKeyword, tok::kw_break, "break");
return Data->replaceChild<BreakStmtSyntax>(NewBreakKeyword,
Cursor::BreakKeyword);
}
RC<TokenSyntax> BreakStmtSyntax::getLabel() const {
return cast<TokenSyntax>(getRaw()->getChild(Cursor::Label));
}
BreakStmtSyntax BreakStmtSyntax::withLabel(RC<TokenSyntax> NewLabel) const {
assert(NewLabel->getTokenKind() == tok::identifier);
return Data->replaceChild<BreakStmtSyntax>(NewLabel, Cursor::Label);
}
#pragma mark - continue-statement Data
ContinueStmtSyntaxData::ContinueStmtSyntaxData(RC<RawSyntax> Raw,
const SyntaxData *Parent,
CursorIndex IndexInParent)
: StmtSyntaxData(Raw, Parent, IndexInParent) {
assert(Raw->Layout.size() == 2);
syntax_assert_child_token_text(Raw,
ContinueStmtSyntax::Cursor::ContinueKeyword,
tok::kw_continue, "continue");
syntax_assert_child_token(Raw, ContinueStmtSyntax::Cursor::Label,
tok::identifier);
}
RC<ContinueStmtSyntaxData>
ContinueStmtSyntaxData::make(RC<RawSyntax> Raw, const SyntaxData *Parent,
CursorIndex IndexInParent) {
return RC<ContinueStmtSyntaxData> {
new ContinueStmtSyntaxData {
Raw, Parent, IndexInParent
}
};
}
RC<ContinueStmtSyntaxData> ContinueStmtSyntaxData::makeBlank() {
return make(RawSyntax::make(SyntaxKind::ContinueStmt,
{
TokenSyntax::missingToken(tok::kw_continue,
"continue"),
TokenSyntax::missingToken(tok::identifier, ""),
},
SourcePresence::Present));
}
#pragma mark - continue-statement API
ContinueStmtSyntax::ContinueStmtSyntax(const RC<SyntaxData> Root,
ContinueStmtSyntaxData *Data)
: StmtSyntax(Root, Data) {}
ContinueStmtSyntax ContinueStmtSyntax::make(RC<RawSyntax> Raw,
const SyntaxData *Parent,
CursorIndex IndexInParent) {
auto Data = ContinueStmtSyntaxData::make(Raw, Parent, IndexInParent);
return { Data, Data.get() };
}
ContinueStmtSyntax ContinueStmtSyntax::makeBlank() {
auto Data = ContinueStmtSyntaxData::makeBlank();
return { Data, Data.get() };
}
RC<TokenSyntax> ContinueStmtSyntax::getContinueKeyword() const {
return cast<TokenSyntax>(getRaw()->getChild(Cursor::ContinueKeyword));
}
ContinueStmtSyntax ContinueStmtSyntax::
withContinueKeyword(RC<TokenSyntax> NewContinueKeyword) const {
syntax_assert_token_is(NewContinueKeyword, tok::kw_continue, "continue");
return Data->replaceChild<ContinueStmtSyntax>(NewContinueKeyword,
Cursor::ContinueKeyword);
}
RC<TokenSyntax> ContinueStmtSyntax::getLabel() const {
return cast<TokenSyntax>(getRaw()->getChild(Cursor::Label));
}
ContinueStmtSyntax
ContinueStmtSyntax::withLabel(RC<TokenSyntax> NewLabel) const {
assert(NewLabel->getTokenKind() == tok::identifier);
return Data->replaceChild<ContinueStmtSyntax>(NewLabel, Cursor::Label);
}
#pragma mark - return-statement Data
ReturnStmtSyntaxData::ReturnStmtSyntaxData(RC<RawSyntax> Raw,
const SyntaxData *Parent,
CursorIndex IndexInParent)
: StmtSyntaxData(Raw, Parent, IndexInParent) {
assert(Raw->Layout.size() == 2);
syntax_assert_child_token_text(Raw,
ReturnStmtSyntax::Cursor::ReturnKeyword,
tok::kw_return, "return");
assert(Raw->getChild(ReturnStmtSyntax::Cursor::Expression)->isExpr());
}
RC<ReturnStmtSyntaxData>
ReturnStmtSyntaxData::make(RC<RawSyntax> Raw, const SyntaxData *Parent,
CursorIndex IndexInParent) {
return RC<ReturnStmtSyntaxData> {
new ReturnStmtSyntaxData {
Raw, Parent, IndexInParent
}
};
}
RC<ReturnStmtSyntaxData> ReturnStmtSyntaxData::makeBlank() {
return make(RawSyntax::make(SyntaxKind::ReturnStmt,
{
TokenSyntax::missingToken(tok::kw_return,
"return"),
RawSyntax::missing(SyntaxKind::MissingExpr),
},
SourcePresence::Present));
}
#pragma mark - return-statement API
ReturnStmtSyntax::ReturnStmtSyntax(const RC<SyntaxData> Root,
const ReturnStmtSyntaxData *Data)
: StmtSyntax(Root, Data) {}
ReturnStmtSyntax ReturnStmtSyntax::make(RC<RawSyntax> Raw,
const SyntaxData *Parent,
CursorIndex IndexInParent) {
auto Data = ReturnStmtSyntaxData::make(Raw, Parent, IndexInParent);
return { Data, Data.get() };
}
ReturnStmtSyntax ReturnStmtSyntax::makeBlank() {
auto Data = ReturnStmtSyntaxData::makeBlank();
return { Data, Data.get() };
}
RC<TokenSyntax> ReturnStmtSyntax::getReturnKeyword() const {
return cast<TokenSyntax>(getRaw()->getChild(Cursor::ReturnKeyword));
}
ReturnStmtSyntax ReturnStmtSyntax::
withReturnKeyword(RC<TokenSyntax> NewReturnKeyword) const {
syntax_assert_token_is(NewReturnKeyword, tok::kw_return, "return");
return Data->replaceChild<ReturnStmtSyntax>(NewReturnKeyword,
Cursor::ReturnKeyword);
}
Optional<ExprSyntax> ReturnStmtSyntax::getExpression() const {
auto RawExpression = getRaw()->getChild(Cursor::Expression);
if (RawExpression->isMissing()) {
return llvm::None;
}
auto *MyData = getUnsafeData<ReturnStmtSyntax>();
auto &ChildPtr = *reinterpret_cast<std::atomic<uintptr_t>*>(
&MyData->CachedExpression);
SyntaxData::realizeSyntaxNode<ExprSyntax>(ChildPtr, RawExpression, MyData,
cursorIndex(Cursor::Expression));
return ExprSyntax { Root, MyData->CachedExpression.get() };
}
ReturnStmtSyntax
ReturnStmtSyntax::withExpression(ExprSyntax NewExpression) const {
return Data->replaceChild<ReturnStmtSyntax>(NewExpression.getRaw(),
Cursor::Expression);
}
#pragma mark code-block API
CodeBlockStmtSyntax::CodeBlockStmtSyntax(const RC<SyntaxData> Root,
CodeBlockStmtSyntaxData *Data)
: StmtSyntax(Root, Data) {}
#pragma mark statements Data
StmtListSyntaxData::StmtListSyntaxData(RC<RawSyntax> Raw,
const SyntaxData *Parent,
CursorIndex IndexInParent)
: StmtSyntaxData(Raw, Parent, IndexInParent) {
assert(Raw->Kind == SyntaxKind::StmtList);
}
RC<StmtListSyntaxData> StmtListSyntaxData::make(RC<RawSyntax> Raw,
const SyntaxData *Parent,
CursorIndex IndexInParent) {
return RC<StmtListSyntaxData> {
new StmtListSyntaxData { Raw, Parent, IndexInParent }
};
}
RC<StmtListSyntaxData> StmtListSyntaxData::makeBlank() {
return make(RawSyntax::make(SyntaxKind::StmtList,
{},
SourcePresence::Present));
}
#pragma mark statements API
StmtListSyntax::StmtListSyntax(const RC<SyntaxData> Root,
const StmtListSyntaxData *Data)
: Syntax(Root, Data) {}
StmtListSyntax
StmtListSyntax::withAddedStatement(Syntax AdditionalStatement) const {
auto Layout = getRaw()->Layout;
Layout.push_back(AdditionalStatement.getRaw());
auto NewRaw = RawSyntax::make(SyntaxKind::StmtList, Layout,
getRaw()->Presence);
return Data->replaceSelf<StmtListSyntax>(NewRaw);
}
#pragma mark statements Builder
StmtListSyntaxBuilder &
StmtListSyntaxBuilder::addStatement(Syntax Statement) {
StmtListLayout.push_back(Statement.getRaw());
return *this;
}
StmtListSyntax StmtListSyntaxBuilder::build() const {
auto Raw = RawSyntax::make(SyntaxKind::StmtList, StmtListLayout,
SourcePresence::Present);
auto Data = StmtListSyntaxData::make(Raw);
return StmtListSyntax { Data, Data.get() };
}