Files
swift-mirror/lib/Syntax/ExprSyntax.cpp
David Farler c958cd65eb [Syntax] Allow UnknownSyntax to have children
This will make it easier to incrementally implement syntax nodes,
while allowing us to embed nodes that we do know about inside ones
that we don't.

https://bugs.swift.org/browse/SR-4062
2017-02-28 14:30:57 -08:00

541 lines
19 KiB
C++

//===--- ExprSyntax.cpp - Swift Expression Syntax Impl. -------------------===//
//
// 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/ExprSyntax.h"
#include "swift/Syntax/GenericSyntax.h"
using namespace swift;
using namespace swift::syntax;
#pragma mark - expression Data
RC<ExprSyntaxData> ExprSyntaxData::make(RC<RawSyntax> Raw,
const SyntaxData *Parent,
CursorIndex IndexInParent) {
return RC<ExprSyntaxData> {
new ExprSyntaxData {
Raw, Parent, IndexInParent
}
};
}
RC<ExprSyntaxData> ExprSyntaxData::makeBlank() {
return make(RawSyntax::missing(SyntaxKind::MissingExpr));
}
#pragma mark - expression API
ExprSyntax::ExprSyntax(const RC<SyntaxData> Root, const ExprSyntaxData *Data)
: Syntax(Root, Data) {}
#pragma mark - unknown-expression Data
UnknownExprSyntaxData::UnknownExprSyntaxData(RC<RawSyntax> Raw,
const SyntaxData *Parent,
CursorIndex IndexInParent)
: UnknownSyntaxData(Raw, Parent, IndexInParent) {
assert(Raw->Kind == SyntaxKind::UnknownExpr);
}
RC<UnknownExprSyntaxData>
UnknownExprSyntaxData::make(RC<RawSyntax> Raw,
const SyntaxData *Parent,
CursorIndex IndexInParent) {
auto UnknownRaw = RawSyntax::make(SyntaxKind::UnknownExpr, Raw->Layout,
Raw->Presence);
return RC<UnknownExprSyntaxData> {
new UnknownExprSyntaxData {
UnknownRaw, Parent, IndexInParent
}
};
}
#pragma mark - unknown-expression API
UnknownExprSyntax::UnknownExprSyntax(const RC<SyntaxData> Root,
const UnknownExprSyntaxData *Data)
: UnknownSyntax(Root, Data) {}
#pragma mark - integer-literal-expression Data
IntegerLiteralExprSyntaxData::
IntegerLiteralExprSyntaxData(RC<RawSyntax> Raw,
const SyntaxData *Parent,
CursorIndex IndexInParent)
: ExprSyntaxData(Raw, Parent, IndexInParent) {
assert(Raw->Kind == SyntaxKind::IntegerLiteralExpr);
assert(Raw->Layout.size() == 2);
syntax_assert_child_token(Raw, IntegerLiteralExprSyntax::Cursor::Sign,
tok::oper_prefix);
syntax_assert_child_token(Raw, IntegerLiteralExprSyntax::Cursor::Digits,
tok::integer_literal);
}
RC<IntegerLiteralExprSyntaxData>
IntegerLiteralExprSyntaxData::make(RC<RawSyntax> Raw,
const SyntaxData *Parent,
CursorIndex IndexInParent) {
return RC<IntegerLiteralExprSyntaxData> {
new IntegerLiteralExprSyntaxData {
Raw, Parent, IndexInParent
}
};
}
RC<IntegerLiteralExprSyntaxData> IntegerLiteralExprSyntaxData::makeBlank() {
auto Raw = RawSyntax::make(SyntaxKind::IntegerLiteralExpr,
{
TokenSyntax::missingToken(tok::oper_prefix, ""),
TokenSyntax::missingToken(tok::integer_literal, "")
},
SourcePresence::Present);
return make(Raw);
}
#pragma mark - integer-literal-expression API
IntegerLiteralExprSyntax::
IntegerLiteralExprSyntax(const RC<SyntaxData> Root,
const IntegerLiteralExprSyntaxData *Data)
: ExprSyntax(Root, Data) {}
IntegerLiteralExprSyntax
IntegerLiteralExprSyntax::withDigits(RC<TokenSyntax> NewDigits) const {
assert(NewDigits->getTokenKind() == tok::integer_literal);
return Data->replaceChild<IntegerLiteralExprSyntax>(NewDigits,
Cursor::Digits);
}
#pragma mark - symbolic-reference Data
SymbolicReferenceExprSyntaxData::
SymbolicReferenceExprSyntaxData(RC<RawSyntax> Raw, const SyntaxData *Parent,
CursorIndex IndexInParent)
: ExprSyntaxData(Raw, Parent, IndexInParent) {
assert(Raw->Layout.size() == 2);
syntax_assert_child_token(Raw,
SymbolicReferenceExprSyntax::Cursor::Identifier, tok::identifier);
syntax_assert_child_kind(Raw,
SymbolicReferenceExprSyntax::Cursor::GenericArgumentClause,
SyntaxKind::GenericArgumentClause);
}
RC<SymbolicReferenceExprSyntaxData>
SymbolicReferenceExprSyntaxData::make(RC<RawSyntax> Raw,
const SyntaxData *Parent,
CursorIndex IndexInParent) {
return RC<SymbolicReferenceExprSyntaxData> {
new SymbolicReferenceExprSyntaxData {
Raw, Parent, IndexInParent
}
};
}
RC<SymbolicReferenceExprSyntaxData>
SymbolicReferenceExprSyntaxData::makeBlank() {
auto Raw = RawSyntax::make(SyntaxKind::SymbolicReferenceExpr,
{
TokenSyntax::missingToken(tok::identifier, ""),
RawSyntax::missing(SyntaxKind::GenericArgumentClause),
},
SourcePresence::Present);
return make(Raw);
}
#pragma mark - symbolic-reference API
SymbolicReferenceExprSyntax::
SymbolicReferenceExprSyntax(const RC<SyntaxData> Root, const DataType *Data)
: ExprSyntax(Root, Data) {}
RC<TokenSyntax> SymbolicReferenceExprSyntax::getIdentifier() const {
return cast<TokenSyntax>(getRaw()->getChild(Cursor::Identifier));
}
SymbolicReferenceExprSyntax SymbolicReferenceExprSyntax::
withIdentifier(RC<TokenSyntax> NewIdentifier) const {
assert(NewIdentifier->getTokenKind() == tok::identifier);
return Data->replaceChild<SymbolicReferenceExprSyntax>(NewIdentifier,
Cursor::Identifier);
}
llvm::Optional<GenericArgumentClauseSyntax>
SymbolicReferenceExprSyntax::getGenericArgumentClause() const {
auto RawClause = getRaw()->getChild(Cursor::GenericArgumentClause);
if (RawClause->isMissing()) {
return llvm::None;
}
auto *MyData = getUnsafeData<SymbolicReferenceExprSyntax>();
auto &ChildPtr = *reinterpret_cast<std::atomic<uintptr_t>*>(
&MyData->CachedGenericArgClause);
SyntaxData::realizeSyntaxNode<GenericArgumentClauseSyntax>(ChildPtr,
RawClause, MyData,
cursorIndex(Cursor::GenericArgumentClause));
return llvm::Optional<GenericArgumentClauseSyntax> {
GenericArgumentClauseSyntax {
Root,
MyData->CachedGenericArgClause.get()
}
};
}
SymbolicReferenceExprSyntax SymbolicReferenceExprSyntax::
withGenericArgumentClause(GenericArgumentClauseSyntax NewGenericArgs) const {
return Data->replaceChild<SymbolicReferenceExprSyntax>(
NewGenericArgs.getRaw(), Cursor::GenericArgumentClause);
}
#pragma mark - function-call-argument Data
FunctionCallArgumentSyntaxData::
FunctionCallArgumentSyntaxData(RC<RawSyntax> Raw,
const SyntaxData *Parent,
CursorIndex IndexInParent)
: SyntaxData(Raw, Parent, IndexInParent) {
syntax_assert_child_token(Raw, FunctionCallArgumentSyntax::Cursor::Label,
tok::identifier);
syntax_assert_child_token_text(Raw,
FunctionCallArgumentSyntax::Cursor::Colon,
tok::colon, ":");
assert(
Raw->getChild(FunctionCallArgumentSyntax::Cursor::Expression)->isExpr());
syntax_assert_child_token_text(Raw,
FunctionCallArgumentSyntax::Cursor::Comma,
tok::comma, ",");
}
RC<FunctionCallArgumentSyntaxData>
FunctionCallArgumentSyntaxData::make(RC<RawSyntax> Raw,
const SyntaxData *Parent,
CursorIndex IndexInParent) {
return RC<FunctionCallArgumentSyntaxData> {
new FunctionCallArgumentSyntaxData {
Raw, Parent, IndexInParent
}
};
}
RC<FunctionCallArgumentSyntaxData> FunctionCallArgumentSyntaxData::makeBlank() {
auto Raw = RawSyntax::make(SyntaxKind::FunctionCallArgument,
{
TokenSyntax::missingToken(tok::identifier, ""),
TokenSyntax::missingToken(tok::colon, ":"),
RawSyntax::missing(SyntaxKind::MissingExpr),
TokenSyntax::missingToken(tok::comma, ",")
},
SourcePresence::Present);
return make(Raw);
}
#pragma mark - function-call-argument API
FunctionCallArgumentSyntax::
FunctionCallArgumentSyntax(const RC<SyntaxData> Root, const DataType *Data)
: Syntax(Root, Data) {}
RC<TokenSyntax> FunctionCallArgumentSyntax::getLabel() const {
return cast<TokenSyntax>(getRaw()->getChild(Cursor::Label));
}
FunctionCallArgumentSyntax
FunctionCallArgumentSyntax::withLabel(RC<TokenSyntax> NewLabel) const {
assert(NewLabel->getTokenKind() == tok::identifier);
return Data->replaceChild<FunctionCallArgumentSyntax>(NewLabel,
Cursor::Label);
}
RC<TokenSyntax> FunctionCallArgumentSyntax::getColonToken() const {
return cast<TokenSyntax>(getRaw()->getChild(Cursor::Colon));
}
FunctionCallArgumentSyntax
FunctionCallArgumentSyntax::withColonToken(RC<TokenSyntax> NewColon) const {
syntax_assert_token_is(NewColon, tok::colon, ":");
return Data->replaceChild<FunctionCallArgumentSyntax>(NewColon,
Cursor::Colon);
}
llvm::Optional<ExprSyntax> FunctionCallArgumentSyntax::getExpression() const {
auto RawExpression = getRaw()->getChild(Cursor::Expression);
if (RawExpression->isMissing()) {
return llvm::None;
}
auto *MyData = getUnsafeData<FunctionCallArgumentSyntax>();
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() };
}
FunctionCallArgumentSyntax
FunctionCallArgumentSyntax::withExpression(ExprSyntax NewExpression) const {
return Data->replaceChild<FunctionCallArgumentSyntax>(NewExpression.getRaw(),
Cursor::Expression);
}
RC<TokenSyntax> FunctionCallArgumentSyntax::getTrailingComma() const {
return cast<TokenSyntax>(getRaw()->getChild(Cursor::Comma));
}
FunctionCallArgumentSyntax FunctionCallArgumentSyntax::
withTrailingComma(RC<TokenSyntax> NewTrailingComma) const {
syntax_assert_token_is(NewTrailingComma, tok::comma, ",");
return Data->replaceChild<FunctionCallArgumentSyntax>(NewTrailingComma,
FunctionCallArgumentSyntax::Cursor::Comma);
}
#pragma mark - function-call-argument-list Data
FunctionCallArgumentListSyntaxData::
FunctionCallArgumentListSyntaxData(const RC<RawSyntax> Raw,
const SyntaxData *Parent,
CursorIndex IndexInParent)
: SyntaxData(Raw, Parent, IndexInParent) {
#ifndef NDEBUG
for (auto Child : Raw->Layout) {
assert(Child->Kind == SyntaxKind::FunctionCallArgument);
}
#endif
for (size_t i = 0; i < Raw->Layout.size(); ++i) {
CachedArguments.emplace_back(nullptr);
}
}
RC<FunctionCallArgumentListSyntaxData>
FunctionCallArgumentListSyntaxData::make(RC<RawSyntax> Raw,
const SyntaxData *Parent,
CursorIndex IndexInParent) {
return RC<FunctionCallArgumentListSyntaxData> {
new FunctionCallArgumentListSyntaxData {
Raw, Parent, IndexInParent
}
};
}
RC<FunctionCallArgumentListSyntaxData>
FunctionCallArgumentListSyntaxData::makeBlank() {
auto Raw = RawSyntax::make(SyntaxKind::FunctionCallArgumentList, {},
SourcePresence::Present);
return make(Raw);
}
#pragma mark - function-call-argument-list API
FunctionCallArgumentListSyntax::
FunctionCallArgumentListSyntax(const RC<SyntaxData> Root,
const DataType *Data)
: Syntax(Root, Data) {}
size_t
FunctionCallArgumentListSyntax::getNumArguments() const {
return getRaw()->Layout.size();
}
FunctionCallArgumentSyntax
FunctionCallArgumentListSyntax::getArgument(size_t Index) const {
assert(Index <= getRaw()->Layout.size());
auto RawArg = getRaw()->Layout[Index];
auto *MyData = getUnsafeData<FunctionCallArgumentListSyntax>();
auto &ChildPtr = *reinterpret_cast<std::atomic<uintptr_t>*>(
MyData->CachedArguments.data() + Index);
SyntaxData::realizeSyntaxNode<FunctionCallArgumentSyntax>(ChildPtr, RawArg,
MyData,
Index);
return FunctionCallArgumentSyntax {
Root,
MyData->CachedArguments[Index].get()
};
}
FunctionCallArgumentListSyntax
FunctionCallArgumentListSyntax::withAdditionalArgument(
FunctionCallArgumentSyntax AdditionalArgument) const {
auto NewRaw = getRaw()->append(AdditionalArgument.getRaw());
return Data->replaceSelf<FunctionCallArgumentListSyntax>(NewRaw);
}
#pragma mark - function-call-expression Data
RC<FunctionCallArgumentListSyntaxData> CachedArgumentList;
FunctionCallExprSyntaxData::FunctionCallExprSyntaxData(RC<RawSyntax> Raw,
const SyntaxData *Parent,
CursorIndex IndexInParent)
: ExprSyntaxData(Raw, Parent, IndexInParent) {
assert(Raw->Layout.size() == 4);
assert(Raw->getChild(FunctionCallExprSyntax::Cursor::CalledExpression)
->isExpr());
syntax_assert_child_token_text(Raw, FunctionCallExprSyntax::Cursor::LeftParen,
tok::l_paren, "(");
syntax_assert_child_kind(Raw, FunctionCallExprSyntax::Cursor::ArgumentList,
SyntaxKind::FunctionCallArgumentList);
syntax_assert_child_token_text(Raw,
FunctionCallExprSyntax::Cursor::RightParen,
tok::r_paren, ")");
}
RC<FunctionCallExprSyntaxData>
FunctionCallExprSyntaxData::make(RC<RawSyntax> Raw, const SyntaxData *Parent,
CursorIndex IndexInParent) {
return RC<FunctionCallExprSyntaxData> {
new FunctionCallExprSyntaxData {
Raw, Parent, IndexInParent
}
};
}
RC<FunctionCallExprSyntaxData> FunctionCallExprSyntaxData::makeBlank() {
auto Raw = RawSyntax::make(SyntaxKind::FunctionCallExpr,
{
RawSyntax::missing(SyntaxKind::MissingExpr),
TokenSyntax::missingToken(tok::l_paren, "("),
RawSyntax::missing(SyntaxKind::FunctionCallArgumentList),
TokenSyntax::missingToken(tok::r_paren, ")"),
},
SourcePresence::Present);
return make(Raw);
}
#pragma mark - function-call-expression API
FunctionCallExprSyntax::FunctionCallExprSyntax(const RC<SyntaxData> Root,
const DataType *Data)
: ExprSyntax(Root, Data) {}
ExprSyntax FunctionCallExprSyntax::getCalledExpression() const {
auto RawArg = getRaw()->getChild(Cursor::CalledExpression);
auto *MyData = getUnsafeData<FunctionCallExprSyntax>();
auto &ChildPtr = *reinterpret_cast<std::atomic<uintptr_t>*>(
&MyData->CachedCalledExpression);
SyntaxData::realizeSyntaxNode<ExprSyntax>(
ChildPtr, RawArg, MyData, cursorIndex(Cursor::CalledExpression));
return ExprSyntax {
Root,
MyData->CachedCalledExpression.get(),
};
}
FunctionCallExprSyntax FunctionCallExprSyntax::
withCalledExpression(ExprSyntax NewBaseExpression) const {
return Data->replaceChild<FunctionCallExprSyntax>(NewBaseExpression.getRaw(),
Cursor::CalledExpression);
}
RC<TokenSyntax> FunctionCallExprSyntax::getLeftParen() const {
return cast<TokenSyntax>(getRaw()->getChild(Cursor::LeftParen));
}
FunctionCallExprSyntax
FunctionCallExprSyntax::withLeftParen(RC<TokenSyntax> NewLeftParen) const {
syntax_assert_token_is(NewLeftParen, tok::l_paren, "(");
return Data->replaceChild<FunctionCallExprSyntax>(NewLeftParen,
Cursor::LeftParen);
}
FunctionCallArgumentListSyntax FunctionCallExprSyntax::getArgumentList() const {
auto RawArg = getRaw()->getChild(Cursor::ArgumentList);
auto *MyData = getUnsafeData<FunctionCallExprSyntax>();
auto &ChildPtr = *reinterpret_cast<std::atomic<uintptr_t>*>(
&MyData->CachedArgumentList);
SyntaxData::realizeSyntaxNode<FunctionCallArgumentListSyntax>(
ChildPtr, RawArg, MyData, cursorIndex(Cursor::ArgumentList));
return FunctionCallArgumentListSyntax {
Root,
MyData->CachedArgumentList.get(),
};
}
FunctionCallExprSyntax FunctionCallExprSyntax::
withArgumentList(FunctionCallArgumentListSyntax NewArgumentList) const {
return Data->replaceChild<FunctionCallExprSyntax>(NewArgumentList.getRaw(),
Cursor::ArgumentList);
}
RC<TokenSyntax> FunctionCallExprSyntax::getRightParen() const {
return cast<TokenSyntax>(getRaw()->getChild(Cursor::RightParen));
}
FunctionCallExprSyntax
FunctionCallExprSyntax::withRightParen(RC<TokenSyntax> NewRightParen) const {
syntax_assert_token_is(NewRightParen, tok::r_paren, ")");
return Data->replaceChild<FunctionCallExprSyntax>(NewRightParen,
Cursor::RightParen);
}
#pragma mark - function-call-expression Builder
FunctionCallExprSyntaxBuilder::FunctionCallExprSyntaxBuilder()
: CallLayout(FunctionCallExprSyntaxData::makeBlank()->getRaw()->Layout),
ListLayout(
FunctionCallArgumentListSyntaxData::makeBlank()->getRaw()->Layout) {}
FunctionCallExprSyntaxBuilder &
FunctionCallExprSyntaxBuilder::useLeftParen(RC<TokenSyntax> LeftParen) {
syntax_assert_token_is(LeftParen, tok::l_paren, "(");
CallLayout[cursorIndex(FunctionCallExprSyntax::Cursor::LeftParen)]
= LeftParen;
return *this;
}
FunctionCallExprSyntaxBuilder &FunctionCallExprSyntaxBuilder::
appendArgument(FunctionCallArgumentSyntax AdditionalArgument) {
ListLayout.push_back(AdditionalArgument.getRaw());
return *this;
}
FunctionCallExprSyntaxBuilder &FunctionCallExprSyntaxBuilder::
useCalledExpression(ExprSyntax CalledExpression) {
CallLayout[cursorIndex(FunctionCallExprSyntax::Cursor::CalledExpression)]
= CalledExpression.getRaw();
return *this;
}
FunctionCallExprSyntaxBuilder &
FunctionCallExprSyntaxBuilder::useRightParen(RC<TokenSyntax> RightParen) {
syntax_assert_token_is(RightParen, tok::r_paren, ")");
CallLayout[cursorIndex(FunctionCallExprSyntax::Cursor::RightParen)]
= RightParen;
return *this;
}
FunctionCallExprSyntax FunctionCallExprSyntaxBuilder::build() const {
auto RawArgs = RawSyntax::make(SyntaxKind::FunctionCallArgumentList,
ListLayout, SourcePresence::Present);
auto RawCall = RawSyntax::make(SyntaxKind::FunctionCallExpr, CallLayout,
SourcePresence::Present)
->replaceChild(FunctionCallExprSyntax::Cursor::ArgumentList, RawArgs);
auto Data = FunctionCallExprSyntaxData::make(RawCall);
return { Data, Data.get() };
}