Implement function-signature in lib/Syntax

Part of:
https://bugs.swift.org/browse/SR-4043
This commit is contained in:
David Farler
2017-03-02 12:13:15 -08:00
parent e70a65882f
commit 288da665e3
6 changed files with 378 additions and 13 deletions

View File

@@ -510,6 +510,7 @@ class FunctionParameterListSyntax final : public
friend struct SyntaxFactory;
friend class Syntax;
friend class SyntaxData;
friend class FunctionSignatureSyntax;
using DataType = FunctionParameterListSyntaxData;
@@ -526,11 +527,23 @@ public:
#pragma mark - function-signature Data
class FunctionSignatureSyntaxData final : public SyntaxData {
friend struct SyntaxFactory;
friend class SyntaxData;
friend class FunctionSignatureSyntax;
RC<FunctionParameterListSyntaxData> CachedParameterList;
RC<TypeAttributesSyntaxData> CachedReturnTypeAttributes;
RC<TypeSyntaxData> CachedReturnTypeSyntax;
FunctionSignatureSyntaxData(const RC<RawSyntax> Raw,
const SyntaxData *Parent = nullptr,
const CursorIndex IndexInParent = 0);
static RC<FunctionSignatureSyntaxData>
make(RC<RawSyntax> Raw, const SyntaxData *Parent = nullptr,
CursorIndex IndexInParent = 0);
static RC<FunctionSignatureSyntaxData> makeBlank();
public:
static bool classof(const SyntaxData *SD) {
return SD->getKind() == SyntaxKind::FunctionSignature;
@@ -547,8 +560,6 @@ class FunctionSignatureSyntax final : public Syntax {
friend class SyntaxData;
friend class FunctionSignatureSyntaxData;
using DataType = FunctionSignatureSyntaxData;
enum class Cursor : CursorIndex {
LeftParen,
ParameterList,
@@ -560,6 +571,12 @@ class FunctionSignatureSyntax final : public Syntax {
};
public:
using DataType = FunctionSignatureSyntaxData;
static constexpr SyntaxKind Kind = SyntaxKind::FunctionSignature;
FunctionSignatureSyntax(const RC<SyntaxData> Root, const DataType *Data)
: Syntax(Root, Data) {}
/// Return the left parenthesis '(' token enclosing the parameter list.
RC<TokenSyntax> getLeftParenToken() const;
@@ -575,6 +592,14 @@ public:
FunctionSignatureSyntax
withParameterList(FunctionParameterListSyntax NewParameterList) const;
/// Return the right parenthesis ')' token enclosing the parameter list.
RC<TokenSyntax> getRightParenToken() const;
/// Return a FunctionSignatureSyntax with the given right parentesis ')' token
/// enclosing the parameter list.
FunctionSignatureSyntax
withRightParenToken(RC<TokenSyntax> NewRightParen) const;
/// Return the 'throws' token in this signature if it exists.
RC<TokenSyntax> getThrowsToken() const;
@@ -607,14 +632,6 @@ public:
/// Return a FunctionSignatureSyntax with the given return type.
FunctionSignatureSyntax withReturnTypeSyntax(TypeSyntax NewReturnType) const;
/// Return the right parenthesis ')' token enclosing the parameter list.
RC<TokenSyntax> getRightParenToken() const;
/// Return a FunctionSignatureSyntax with the given right parentesis ')' token
/// enclosing the parameter list.
FunctionSignatureSyntax
withRightParenToken(RC<TokenSyntax> NewLeftParen) const;
static bool classof(const Syntax *S) {
return S->getKind() == SyntaxKind::FunctionSignature;
}

View File

@@ -73,6 +73,8 @@ struct SyntaxFactory {
/// Make an empty list of declaration members.
static DeclMembersSyntax makeBlankDeclMembers();
#pragma mark - function-parameter
/// Make a function parameter with the given elements.
static FunctionParameterSyntax
makeFunctionParameter(RC<TokenSyntax> ExternalName, RC<TokenSyntax> LocalName,
@@ -86,6 +88,8 @@ struct SyntaxFactory {
/// Make a function parameter with all elements marked as missing.
static FunctionParameterSyntax makeBlankFunctionParameter();
#pragma mark - function-parameter-list
/// Make a function parameter list with the given parameters.
static FunctionParameterListSyntax makeFunctionParameterList(
const std::vector<FunctionParameterSyntax> &Parameters);
@@ -93,6 +97,8 @@ struct SyntaxFactory {
/// Make an empty function parameter list.
static FunctionParameterListSyntax makeBlankFunctionParameterList();
#pragma mark - function-signature
/// Make a function signature with the given elements.
static FunctionSignatureSyntax
makeFunctionSignature(RC<TokenSyntax> LeftParen,

View File

@@ -186,13 +186,15 @@ class TypeAttributesSyntax final : public Syntax {
friend struct SyntaxFactory;
friend class TypeAttributesSyntaxData;
friend class SyntaxData;
friend class FunctionSignatureSyntax;
using DataType = TypeAttributesSyntaxData;
TypeAttributesSyntax(RC<SyntaxData> Root,
const TypeAttributesSyntaxData *Data);
public:
// TODO: TODO: TypeAttributesSyntax::getAttribute
// TODO: Convert to SyntaxCollection
//
TypeAttributesSyntax
addTypeAttribute(TypeAttributeSyntax NewTypeAttribute) const;
@@ -236,6 +238,7 @@ class TypeSyntax : public Syntax {
using DataType = TypeSyntaxData;
friend class SyntaxData;
friend class FunctionParameterSyntax;
friend class FunctionSignatureSyntax;
protected:
TypeSyntax(const RC<SyntaxData> Root, const TypeSyntaxData *Data);
public:

View File

@@ -540,3 +540,195 @@ withTrailingComma(RC<TokenSyntax> NewTrailingComma) const {
return Data->replaceChild<FunctionParameterSyntax>(NewTrailingComma,
Cursor::TrailingComma);
}
#pragma mark - function-signature Data
FunctionSignatureSyntaxData::
FunctionSignatureSyntaxData(const RC<RawSyntax> Raw,
const SyntaxData *Parent,
const CursorIndex IndexInParent)
: SyntaxData(Raw, Parent, IndexInParent) {
assert(Raw->Layout.size() == 7);
syntax_assert_child_token_text(Raw,
FunctionSignatureSyntax::Cursor::LeftParen,
tok::l_paren, "(");
assert(Raw->getChild(FunctionSignatureSyntax::Cursor::ParameterList)->Kind ==
SyntaxKind::FunctionParameterList);
syntax_assert_child_token_text(Raw,
FunctionSignatureSyntax::Cursor::RightParen,
tok::r_paren, ")");
#ifndef NDEBUG
auto ThrowsRethrows = cast<TokenSyntax>(
Raw->getChild(FunctionSignatureSyntax::Cursor::ThrowsOrRethrows));
assert(cast<TokenSyntax>(ThrowsRethrows)->getTokenKind() == tok::kw_throws ||
cast<TokenSyntax>(ThrowsRethrows)->getTokenKind() == tok::kw_rethrows);
#endif
syntax_assert_child_token_text(Raw, FunctionSignatureSyntax::Cursor::Arrow,
tok::arrow, "->");
syntax_assert_child_kind(Raw,
FunctionSignatureSyntax::Cursor::ReturnTypeAttributes,
SyntaxKind::TypeAttributes);
assert(Raw->getChild(FunctionSignatureSyntax::Cursor::ReturnType)->isType());
}
RC<FunctionSignatureSyntaxData>
FunctionSignatureSyntaxData::make(RC<RawSyntax> Raw, const SyntaxData *Parent,
CursorIndex IndexInParent) {
return RC<FunctionSignatureSyntaxData> {
new FunctionSignatureSyntaxData {
Raw, Parent, IndexInParent
}
};
}
RC<FunctionSignatureSyntaxData> FunctionSignatureSyntaxData::makeBlank() {
auto Raw = RawSyntax::make(SyntaxKind::FunctionSignature,
{
TokenSyntax::missingToken(tok::l_paren, "("),
RawSyntax::missing(SyntaxKind::FunctionParameterList),
TokenSyntax::missingToken(tok::r_paren, ")"),
TokenSyntax::missingToken(tok::kw_throws, "throws"),
TokenSyntax::missingToken(tok::arrow, "->"),
RawSyntax::missing(SyntaxKind::TypeAttributes),
RawSyntax::missing(SyntaxKind::MissingType),
},
SourcePresence::Present);
return make(Raw);
}
#pragma mark - function-signature API
RC<TokenSyntax> FunctionSignatureSyntax::getLeftParenToken() const {
return cast<TokenSyntax>(getRaw()->getChild(Cursor::LeftParen));
}
FunctionSignatureSyntax FunctionSignatureSyntax::
withLeftParenToken(RC<TokenSyntax> NewLeftParen) const {
syntax_assert_token_is(NewLeftParen, tok::l_paren, "(");
return Data->replaceChild<FunctionSignatureSyntax>(NewLeftParen,
Cursor::LeftParen);
}
FunctionParameterListSyntax FunctionSignatureSyntax::getParameterList() const {
auto RawList = getRaw()->getChild(Cursor::ParameterList);
auto *MyData = getUnsafeData<FunctionSignatureSyntax>();
auto &ChildPtr = *reinterpret_cast<std::atomic<uintptr_t>*>(
&MyData->CachedParameterList);
SyntaxData::realizeSyntaxNode<FunctionParameterListSyntax>(ChildPtr, RawList,
MyData, cursorIndex(Cursor::ParameterList));
return FunctionParameterListSyntax {
Root,
MyData->CachedParameterList.get()
};
}
FunctionSignatureSyntax FunctionSignatureSyntax::
withParameterList(FunctionParameterListSyntax NewParameterList) const {
return Data->replaceChild<FunctionSignatureSyntax>(NewParameterList.getRaw(),
Cursor::ParameterList);
}
RC<TokenSyntax> FunctionSignatureSyntax::getRightParenToken() const {
return cast<TokenSyntax>(getRaw()->getChild(Cursor::RightParen));
}
FunctionSignatureSyntax FunctionSignatureSyntax::
withRightParenToken(RC<TokenSyntax> NewRightParen) const {
syntax_assert_token_is(NewRightParen, tok::r_paren, ")");
return Data->replaceChild<FunctionSignatureSyntax>(NewRightParen,
Cursor::RightParen);
}
RC<TokenSyntax> FunctionSignatureSyntax::getThrowsToken() const {
auto Throw = cast<TokenSyntax>(getRaw()->getChild(Cursor::ThrowsOrRethrows));
if (Throw->getTokenKind() != tok::kw_throws) {
return TokenSyntax::missingToken(tok::kw_throws, "throws");
}
return Throw;
}
FunctionSignatureSyntax FunctionSignatureSyntax::
withThrowsToken(RC<TokenSyntax> NewThrowsToken) const {
syntax_assert_token_is(NewThrowsToken, tok::kw_throws, "throws");
return Data->replaceChild<FunctionSignatureSyntax>(NewThrowsToken,
Cursor::ThrowsOrRethrows);
}
RC<TokenSyntax> FunctionSignatureSyntax::getRethrowsToken() const {
auto Rethrow = cast<TokenSyntax>(
getRaw()->getChild(Cursor::ThrowsOrRethrows));
if (Rethrow->getTokenKind() != tok::kw_rethrows) {
return TokenSyntax::missingToken(tok::kw_rethrows, "rethrows");
}
return Rethrow;
}
FunctionSignatureSyntax FunctionSignatureSyntax::
withRethrowsToken(RC<TokenSyntax> NewRethrowsToken) const {
syntax_assert_token_is(NewRethrowsToken, tok::kw_rethrows, "rethrows");
return Data->replaceChild<FunctionSignatureSyntax>(NewRethrowsToken,
Cursor::ThrowsOrRethrows);
}
RC<TokenSyntax> FunctionSignatureSyntax::getArrowToken() const {
return cast<TokenSyntax>(getRaw()->getChild(Cursor::Arrow));
}
FunctionSignatureSyntax FunctionSignatureSyntax::
withArrowToken(RC<TokenSyntax> NewArrowToken) const {
syntax_assert_token_is(NewArrowToken, tok::arrow, "->");
return Data->replaceChild<FunctionSignatureSyntax>(NewArrowToken,
Cursor::Arrow);
}
TypeAttributesSyntax FunctionSignatureSyntax::getReturnTypeAttributes() const {
auto RawAttrs = getRaw()->getChild(Cursor::ReturnTypeAttributes);
auto *MyData = getUnsafeData<FunctionSignatureSyntax>();
auto &ChildPtr = *reinterpret_cast<std::atomic<uintptr_t>*>(
&MyData->CachedReturnTypeAttributes);
SyntaxData::realizeSyntaxNode<TypeAttributesSyntax>(ChildPtr, RawAttrs,
MyData, cursorIndex(Cursor::ReturnTypeAttributes));
return TypeAttributesSyntax {
Root,
MyData->CachedReturnTypeAttributes.get()
};
}
FunctionSignatureSyntax FunctionSignatureSyntax::
withReturnTypeAttributes(TypeAttributesSyntax NewAttributes) const {
return Data->replaceChild<FunctionSignatureSyntax>(NewAttributes.getRaw(),
Cursor::ReturnTypeAttributes);
}
TypeSyntax FunctionSignatureSyntax::getReturnTypeSyntax() const {
auto RawType = getRaw()->getChild(Cursor::ReturnType);
auto *MyData = getUnsafeData<FunctionSignatureSyntax>();
auto &ChildPtr = *reinterpret_cast<std::atomic<uintptr_t>*>(
&MyData->CachedReturnTypeSyntax);
SyntaxData::realizeSyntaxNode<TypeSyntax>(ChildPtr, RawType,
MyData, cursorIndex(Cursor::ReturnType));
return TypeSyntax {
Root,
MyData->CachedReturnTypeSyntax.get()
};
}
FunctionSignatureSyntax FunctionSignatureSyntax::
withReturnTypeSyntax(TypeSyntax NewReturnTypeSyntax) const {
return Data->replaceChild<FunctionSignatureSyntax>(
NewReturnTypeSyntax.getRaw(), Cursor::ReturnType);
}

View File

@@ -92,6 +92,8 @@ DeclMembersSyntax SyntaxFactory::makeBlankDeclMembers() {
return DeclMembersSyntax { Data, Data.get() };
}
#pragma mark - function-parameter
FunctionParameterSyntax SyntaxFactory::
makeFunctionParameter(RC<TokenSyntax> ExternalName,
RC<TokenSyntax> LocalName,
@@ -126,7 +128,10 @@ FunctionParameterSyntax SyntaxFactory::makeBlankFunctionParameter() {
return { Data, Data.get() };
}
FunctionParameterListSyntax SyntaxFactory::makeFunctionParameterList(const std::vector<FunctionParameterSyntax> &Parameters) {
#pragma mark - function-parameter-list
FunctionParameterListSyntax SyntaxFactory::makeFunctionParameterList(
const std::vector<FunctionParameterSyntax> &Parameters) {
RawSyntax::LayoutList Layout;
for (auto Param : Parameters) {
Layout.push_back(Param.getRaw());
@@ -143,6 +148,36 @@ FunctionParameterListSyntax SyntaxFactory::makeBlankFunctionParameterList() {
return { Data, Data.get() };
}
#pragma mark - function-signature
FunctionSignatureSyntax
SyntaxFactory::makeFunctionSignature(RC<TokenSyntax> LeftParen,
FunctionParameterListSyntax ParameterList,
RC<TokenSyntax> RightParen,
RC<TokenSyntax> ThrowsOrRethrows,
RC<TokenSyntax> Arrow,
TypeAttributesSyntax ReturnTypeAttributes,
TypeSyntax ReturnTypeSyntax) {
auto Raw = RawSyntax::make(SyntaxKind::FunctionSignature,
{
LeftParen,
ParameterList.getRaw(),
RightParen,
ThrowsOrRethrows,
Arrow,
ReturnTypeAttributes.getRaw(),
ReturnTypeSyntax.getRaw()
},
SourcePresence::Present);
auto Data = FunctionSignatureSyntaxData::make(Raw);
return { Data, Data.get() };
}
FunctionSignatureSyntax SyntaxFactory::makeBlankFunctionSignature() {
auto Data = FunctionSignatureSyntaxData::makeBlank();
return { Data, Data.get() };
}
#pragma mark - Statements
CodeBlockStmtSyntax

View File

@@ -284,16 +284,128 @@ TEST(DeclSyntaxTests, FunctionParameterListMakeAPIs) {
#pragma mark - function-signature
TEST(DeclSyntaxTests, FunctionSignatureMakeAPIs) {
FunctionSignatureSyntax getCannedFunctionSignature() {
auto LParen = SyntaxFactory::makeLeftParenToken({}, {});
auto Param = getCannedFunctionParameter();
auto List = SyntaxFactory::makeBlankFunctionParameterList()
.appending(Param)
.appending(Param)
.appending(Param)
.castTo<FunctionParameterListSyntax>();
auto RParen = SyntaxFactory::makeRightParenToken({}, Trivia::spaces(1));
auto Throws = SyntaxFactory::makeThrowsKeyword({}, Trivia::spaces(1));
auto Arrow = SyntaxFactory::makeArrow({}, Trivia::spaces(1));
auto NoAttributes = SyntaxFactory::makeBlankTypeAttributes();
auto Int = SyntaxFactory::makeTypeIdentifier("Int", {}, {});
return SyntaxFactory::makeFunctionSignature(LParen, List, RParen, Throws,
Arrow, NoAttributes, Int);
}
TEST(DeclSyntaxTests, FunctionSignatureMakeAPIs) {
{
SmallString<1> Scratch;
llvm::raw_svector_ostream OS(Scratch);
SyntaxFactory::makeBlankFunctionSignature().print(OS);
ASSERT_EQ(OS.str().str(), "");
}
{
SmallString<48> Scratch;
llvm::raw_svector_ostream OS(Scratch);
getCannedFunctionSignature().print(OS);
ASSERT_EQ(OS.str().str(),
"(with radius: Int = -1, "
"with radius: Int = -1, "
"with radius: Int = -1, ) throws -> Int");
}
}
TEST(DeclSyntaxTests, FunctionSignatureGetAPIs) {
auto LParen = SyntaxFactory::makeLeftParenToken({}, {});
auto Param = getCannedFunctionParameter();
auto List = SyntaxFactory::makeBlankFunctionParameterList()
.appending(Param)
.appending(Param)
.appending(Param)
.castTo<FunctionParameterListSyntax>();
auto RParen = SyntaxFactory::makeRightParenToken({}, Trivia::spaces(1));
auto Throws = SyntaxFactory::makeThrowsKeyword({}, Trivia::spaces(1));
auto Arrow = SyntaxFactory::makeArrow({}, Trivia::spaces(1));
auto NoAttributes = SyntaxFactory::makeBlankTypeAttributes();
auto Int = SyntaxFactory::makeTypeIdentifier("Int", {}, {});
auto Sig = SyntaxFactory::makeFunctionSignature(LParen, List, RParen, Throws,
Arrow, NoAttributes, Int);
ASSERT_EQ(LParen, Sig.getLeftParenToken());
{
SmallString<48> Scratch;
llvm::raw_svector_ostream OS(Scratch);
auto GottenList1 = Sig.getParameterList();
auto GottenList2 = Sig.getParameterList();
ASSERT_TRUE(GottenList1.hasSameIdentityAs(GottenList2));
GottenList1.print(OS);
ASSERT_EQ(OS.str().str(),
"with radius: Int = -1, "
"with radius: Int = -1, "
"with radius: Int = -1, ");
}
ASSERT_EQ(RParen, Sig.getRightParenToken());
ASSERT_EQ(Throws, Sig.getThrowsToken());
ASSERT_TRUE(Sig.getRethrowsToken()->isMissing());
ASSERT_EQ(Arrow, Sig.getArrowToken());
{
SmallString<48> Scratch;
llvm::raw_svector_ostream OS(Scratch);
auto GottenAttrs1 = Sig.getReturnTypeAttributes();
auto GottenAttrs2 = Sig.getReturnTypeAttributes();
ASSERT_TRUE(GottenAttrs1.hasSameIdentityAs(GottenAttrs2));
ASSERT_EQ(OS.str().str(), "");
}
{
SmallString<3> Scratch;
llvm::raw_svector_ostream OS(Scratch);
auto GottenReturnType1 = Sig.getReturnTypeSyntax();
auto GottenReturnType2 = Sig.getReturnTypeSyntax();
ASSERT_TRUE(GottenReturnType1.hasSameIdentityAs(GottenReturnType2));
GottenReturnType1.print(OS);
ASSERT_EQ(OS.str().str(), "Int");
}
}
TEST(DeclSyntaxTests, FunctionSignatureWithAPIs) {
auto LParen = SyntaxFactory::makeLeftParenToken({}, {});
auto Param = getCannedFunctionParameter();
auto List = SyntaxFactory::makeBlankFunctionParameterList()
.appending(Param)
.appending(Param)
.appending(Param)
.castTo<FunctionParameterListSyntax>();
auto RParen = SyntaxFactory::makeRightParenToken({}, Trivia::spaces(1));
auto Throws = SyntaxFactory::makeThrowsKeyword({}, Trivia::spaces(1));
auto Arrow = SyntaxFactory::makeArrow({}, Trivia::spaces(1));
auto NoAttributes = SyntaxFactory::makeBlankTypeAttributes();
auto Int = SyntaxFactory::makeTypeIdentifier("Int", {}, {});
SmallString<48> Scratch;
llvm::raw_svector_ostream OS(Scratch);
SyntaxFactory::makeBlankFunctionSignature()
.withLeftParenToken(LParen)
.withParameterList(List)
.withRightParenToken(RParen)
.withThrowsToken(Throws)
.withReturnTypeAttributes(NoAttributes)
.withArrowToken(Arrow)
.withReturnTypeSyntax(Int)
.print(OS);
ASSERT_EQ(OS.str().str(),
"(with radius: Int = -1, "
"with radius: Int = -1, "
"with radius: Int = -1, ) throws -> Int");
}
#pragma mark - function-declaration