//===--- DeclSyntax.cpp - Declaration 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/DeclSyntax.h" #include "swift/Syntax/ExprSyntax.h" #include "swift/Syntax/RawSyntax.h" #include "swift/Syntax/SyntaxFactory.h" using namespace swift; using namespace swift::syntax; #pragma mark - declaration Data DeclSyntaxData::DeclSyntaxData(RC Raw, const SyntaxData *Parent, CursorIndex IndexInParent) : SyntaxData(Raw, Parent, IndexInParent) { assert(Raw->isDecl()); } #pragma mark - declaration API DeclSyntax::DeclSyntax(const RC Root, const DeclSyntaxData *Data) : Syntax(Root, Data) {} #pragma mark - unknown-statement Data UnknownDeclSyntaxData::UnknownDeclSyntaxData(RC Raw, const SyntaxData *Parent, CursorIndex IndexInParent) : UnknownSyntaxData(Raw, Parent, IndexInParent) { assert(Raw->Kind == SyntaxKind::UnknownDecl); } RC UnknownDeclSyntaxData::make(RC Raw, const SyntaxData *Parent, CursorIndex IndexInParent) { auto UnknownRaw = RawSyntax::make(SyntaxKind::UnknownDecl, Raw->Layout, Raw->Presence); return RC { new UnknownDeclSyntaxData { Raw, Parent, IndexInParent } }; } #pragma mark - unknown-statement API UnknownDeclSyntax::UnknownDeclSyntax(const RC Root, const UnknownDeclSyntaxData *Data) : UnknownSyntax(Root, Data) {} #pragma mark - declaration-members Data DeclMembersSyntaxData::DeclMembersSyntaxData(RC Raw, const SyntaxData *Parent, CursorIndex IndexInParent) : SyntaxData(Raw, Parent, IndexInParent) { assert(Raw->Kind == SyntaxKind::DeclMembers); } RC DeclMembersSyntaxData::make(RC Raw, const SyntaxData *Parent, CursorIndex IndexInParent) { return RC { new DeclMembersSyntaxData { Raw, Parent, IndexInParent } }; } RC DeclMembersSyntaxData::makeBlank() { return make(RawSyntax::make(SyntaxKind::DeclMembers, {}, SourcePresence::Present)); } #pragma mark - declaration-members API DeclMembersSyntax::DeclMembersSyntax(const RC Root, const DeclMembersSyntaxData *Data) : Syntax(Root, Data) {} #pragma mark - declaration-members Builder DeclMembersSyntaxBuilder & DeclMembersSyntaxBuilder::addMember(DeclSyntax Member) { MembersLayout.push_back(Member.getRaw()); return *this; } DeclMembersSyntax DeclMembersSyntaxBuilder::build() const { auto Raw = RawSyntax::make(SyntaxKind::DeclMembers, MembersLayout, SourcePresence::Present); auto Data = DeclMembersSyntaxData::make(Raw); return DeclMembersSyntax { Data, Data.get() }; } #pragma mark - struct-declaration Data StructDeclSyntaxData::StructDeclSyntaxData(RC Raw, const SyntaxData *Parent, CursorIndex IndexInParent) : DeclSyntaxData(Raw, Parent, IndexInParent) { assert(Raw->Kind == SyntaxKind::StructDecl); syntax_assert_child_token_text(Raw, StructDeclSyntax::Cursor::StructKeyword, tok::kw_struct, "struct"); syntax_assert_child_token(Raw, StructDeclSyntax::Cursor::Identifier, tok::identifier); syntax_assert_child_kind(Raw, StructDeclSyntax::Cursor::GenericParameterClause, SyntaxKind::GenericParameterClause); syntax_assert_child_kind(Raw, StructDeclSyntax::Cursor::GenericWhereClause, SyntaxKind::GenericWhereClause); syntax_assert_child_token_text(Raw, StructDeclSyntax::Cursor::LeftBrace, tok::l_brace, "{"); syntax_assert_child_kind(Raw, StructDeclSyntax::Cursor::Members, SyntaxKind::DeclMembers); syntax_assert_child_token_text(Raw, StructDeclSyntax::Cursor::RightBrace, tok::r_brace, "}"); } RC StructDeclSyntaxData::make(RC Raw, const SyntaxData *Parent, CursorIndex IndexInParent) { return RC { new StructDeclSyntaxData { Raw, Parent, IndexInParent } }; } RC StructDeclSyntaxData::makeBlank() { return make(RawSyntax::make(SyntaxKind::StructDecl, { TokenSyntax::missingToken(tok::kw_struct, "struct"), TokenSyntax::missingToken(tok::identifier, ""), RawSyntax::missing(SyntaxKind::GenericParameterClause), RawSyntax::missing(SyntaxKind::GenericWhereClause), TokenSyntax::missingToken(tok::l_brace, "{"), RawSyntax::missing(SyntaxKind::DeclMembers), TokenSyntax::missingToken(tok::r_brace, "}"), }, SourcePresence::Present)); } #pragma mark - struct-declaration API StructDeclSyntax::StructDeclSyntax(const RC Root, const StructDeclSyntaxData *Data) : DeclSyntax(Root, Data) {} RC StructDeclSyntax::getStructKeyword() const { return cast(getRaw()->getChild(Cursor::StructKeyword)); } StructDeclSyntax StructDeclSyntax::withStructKeyword(RC NewStructKeyword) const { syntax_assert_token_is(NewStructKeyword, tok::kw_struct, "struct"); return Data->replaceChild(NewStructKeyword, Cursor::StructKeyword); } StructDeclSyntax StructDeclSyntax::withLeftBrace(RC NewLeftBrace) const { syntax_assert_token_is(NewLeftBrace, tok::l_brace, "{"); return Data->replaceChild(NewLeftBrace, Cursor::LeftBrace); } RC StructDeclSyntax::getLeftBraceToken() const { return cast(getRaw()->getChild(Cursor::LeftBrace)); } StructDeclSyntax StructDeclSyntax::withMembers(DeclMembersSyntax NewMembers) const { return Data->replaceChild(NewMembers.getRaw(), Cursor::Members); } DeclMembersSyntax StructDeclSyntax::getMembers() const { auto Raw = getRaw()->getChild(Cursor::Members); auto MembersData = DeclMembersSyntaxData::make(Raw, Data, cursorIndex(Cursor::Members)); const_cast(getData())->CachedMembers = MembersData; return DeclMembersSyntax { Root, MembersData.get() }; } #pragma mark - struct-declaration Builder StructDeclSyntaxBuilder::StructDeclSyntaxBuilder() : StructLayout(SyntaxFactory::makeBlankStructDecl().getRaw()->Layout) {} StructDeclSyntaxBuilder & StructDeclSyntaxBuilder::useStructKeyword(RC StructKeyword) { syntax_assert_token_is(StructKeyword, tok::kw_struct, "struct"); auto Index = cursorIndex(StructDeclSyntax::Cursor::StructKeyword); StructLayout[Index] = StructKeyword; return *this; } StructDeclSyntaxBuilder & StructDeclSyntaxBuilder::useIdentifier(RC Identifier) { assert(Identifier->getTokenKind() == tok::identifier); auto Index = cursorIndex(StructDeclSyntax::Cursor::Identifier); StructLayout[Index] = Identifier; return *this; } StructDeclSyntaxBuilder & StructDeclSyntaxBuilder::useLeftBrace(RC LeftBrace) { syntax_assert_token_is(LeftBrace, tok::l_brace, "{"); auto Index = cursorIndex(StructDeclSyntax::Cursor::LeftBrace); StructLayout[Index] = LeftBrace; return *this; } StructDeclSyntaxBuilder & StructDeclSyntaxBuilder::useMembers(DeclMembersSyntax Members) { auto Index = cursorIndex(StructDeclSyntax::Cursor::Members); StructLayout[Index] = Members.getRaw(); return *this; } StructDeclSyntaxBuilder & StructDeclSyntaxBuilder::useRightBrace(RC RightBrace) { syntax_assert_token_is(RightBrace, tok::r_brace, "}"); auto Index = cursorIndex(StructDeclSyntax::Cursor::RightBrace); StructLayout[Index] = RightBrace; return *this; } StructDeclSyntax StructDeclSyntaxBuilder::build() const { auto Raw = RawSyntax::make(SyntaxKind::StructDecl, StructLayout, SourcePresence::Present); auto Data = StructDeclSyntaxData::make(Raw); return StructDeclSyntax { Data, Data.get() }; } #pragma mark - type-alias Data TypeAliasDeclSyntaxData::TypeAliasDeclSyntaxData(RC Raw, const SyntaxData *Parent, CursorIndex IndexInParent) : DeclSyntaxData(Raw, Parent, IndexInParent) {} RC TypeAliasDeclSyntaxData::make(RC Raw, const SyntaxData *Parent, CursorIndex IndexInParent) { return RC { new TypeAliasDeclSyntaxData { Raw, Parent, IndexInParent } }; } RC TypeAliasDeclSyntaxData::makeBlank() { return make(RawSyntax::make(SyntaxKind::TypeAliasDecl, { TokenSyntax::missingToken(tok::kw_typealias, "typealias"), TokenSyntax::missingToken(tok::identifier, ""), RawSyntax::missing(SyntaxKind::GenericParameterClause), TokenSyntax::missingToken(tok::equal, "="), RawSyntax::missing(SyntaxKind::MissingType), }, SourcePresence::Present)); } #pragma mark - type-alias API TypeAliasDeclSyntax::TypeAliasDeclSyntax(RC Root, const TypeAliasDeclSyntaxData *Data) : DeclSyntax(Root, Data) {} TypeAliasDeclSyntax TypeAliasDeclSyntax:: withTypeAliasKeyword(RC NewTypeAliasKeyword) const { syntax_assert_token_is(NewTypeAliasKeyword, tok::kw_typealias, "typealias"); return Data->replaceChild(NewTypeAliasKeyword, Cursor::TypeAliasKeyword); } TypeAliasDeclSyntax TypeAliasDeclSyntax::withIdentifier(RC NewIdentifier) const { assert(NewIdentifier->getTokenKind() == tok::identifier); return Data->replaceChild(NewIdentifier, Cursor::Identifier); } TypeAliasDeclSyntax TypeAliasDeclSyntax:: withGenericParameterClause(GenericParameterClauseSyntax NewGenericParams) const { return Data->replaceChild(NewGenericParams.getRaw(), Cursor::GenericParameterClause); } TypeAliasDeclSyntax TypeAliasDeclSyntax::withEqualToken(RC NewEqualToken) const { syntax_assert_token_is(NewEqualToken, tok::equal, "="); return Data->replaceChild(NewEqualToken, Cursor::EqualToken); } TypeAliasDeclSyntax TypeAliasDeclSyntax::withTypeSyntax(TypeSyntax NewType) const { return Data->replaceChild(NewType.getRaw(), Cursor::Type); } #pragma mark - type-alias Builder TypeAliasDeclSyntaxBuilder::TypeAliasDeclSyntaxBuilder() : TypeAliasLayout(SyntaxFactory::makeBlankTypealiasDecl().getRaw()->Layout) {} TypeAliasDeclSyntaxBuilder &TypeAliasDeclSyntaxBuilder:: useTypeAliasKeyword(RC TypeAliasKeyword) { syntax_assert_token_is(TypeAliasKeyword, tok::kw_typealias, "typealias"); auto Index = cursorIndex(TypeAliasDeclSyntax::Cursor::TypeAliasKeyword); TypeAliasLayout[Index] = TypeAliasKeyword; return *this; } TypeAliasDeclSyntaxBuilder & TypeAliasDeclSyntaxBuilder::useIdentifier(RC Identifier) { assert(Identifier->getTokenKind() == tok::identifier); auto Index = cursorIndex(TypeAliasDeclSyntax::Cursor::Identifier); TypeAliasLayout[Index] = Identifier; return *this; } TypeAliasDeclSyntaxBuilder &TypeAliasDeclSyntaxBuilder:: useGenericParameterClause(GenericParameterClauseSyntax GenericParams) { auto Index = cursorIndex(TypeAliasDeclSyntax::Cursor::GenericParameterClause); TypeAliasLayout[Index] = GenericParams.getRaw(); return *this; } TypeAliasDeclSyntaxBuilder & TypeAliasDeclSyntaxBuilder::useEqualToken(RC EqualToken) { auto Index = cursorIndex(TypeAliasDeclSyntax::Cursor::EqualToken); TypeAliasLayout[Index] = EqualToken; return *this; } TypeAliasDeclSyntaxBuilder & TypeAliasDeclSyntaxBuilder::useType(TypeSyntax ReferentType) { auto Index = cursorIndex(TypeAliasDeclSyntax::Cursor::Type); TypeAliasLayout[Index] = ReferentType.getRaw(); return *this; } TypeAliasDeclSyntax TypeAliasDeclSyntaxBuilder::build() const { auto Raw = RawSyntax::make(SyntaxKind::TypeAliasDecl, TypeAliasLayout, SourcePresence::Present); auto Data = TypeAliasDeclSyntaxData::make(Raw); return { Data, Data.get() }; } #pragma mark - function-parameter Data FunctionParameterSyntaxData::FunctionParameterSyntaxData(RC Raw, const SyntaxData *Parent, CursorIndex IndexInParent) : SyntaxData(Raw, Parent, IndexInParent) { assert(Raw->Layout.size() == 8); syntax_assert_child_token(Raw, FunctionParameterSyntax::Cursor::ExternalName, tok::identifier); syntax_assert_child_token(Raw, FunctionParameterSyntax::Cursor::LocalName, tok::identifier); syntax_assert_child_token_text(Raw, FunctionParameterSyntax::Cursor::Colon, tok::colon, ":"); assert(Raw->getChild(FunctionParameterSyntax::Cursor::Type)->isType()); syntax_assert_child_token_text(Raw, FunctionParameterSyntax::Cursor::Ellipsis, tok::identifier, "..."); syntax_assert_child_token_text(Raw, FunctionParameterSyntax::Cursor::DefaultEqual, tok::equal, "="); assert(Raw->getChild( FunctionParameterSyntax::Cursor::DefaultExpression)->isExpr()); syntax_assert_child_token_text(Raw, FunctionParameterSyntax::Cursor::TrailingComma, tok::comma, ","); } RC FunctionParameterSyntaxData::make(RC Raw, const SyntaxData *Parent, CursorIndex IndexInParent) { return RC { new FunctionParameterSyntaxData { Raw, Parent, IndexInParent } }; } RC FunctionParameterSyntaxData::makeBlank() { auto Raw = RawSyntax::make(SyntaxKind::FunctionParameter, { TokenSyntax::missingToken(tok::identifier, ""), TokenSyntax::missingToken(tok::identifier, ""), TokenSyntax::missingToken(tok::colon, ":"), RawSyntax::missing(SyntaxKind::MissingType), TokenSyntax::missingToken(tok::identifier, "..."), TokenSyntax::missingToken(tok::equal, "="), RawSyntax::missing(SyntaxKind::MissingExpr), TokenSyntax::missingToken(tok::comma, ","), }, SourcePresence::Present); return make(Raw); } #pragma mark - function-parameter API RC FunctionParameterSyntax::getExternalName() const { return cast(getRaw()->getChild(Cursor::ExternalName)); } FunctionParameterSyntax FunctionParameterSyntax:: withExternalName(RC NewExternalName) const { assert(NewExternalName->getTokenKind() == tok::identifier); return Data->replaceChild(NewExternalName, Cursor::ExternalName); } RC FunctionParameterSyntax::getLocalName() const { return cast(getRaw()->getChild(Cursor::LocalName)); } FunctionParameterSyntax FunctionParameterSyntax:: withLocalName(RC NewLocalName) const { assert(NewLocalName->getTokenKind() == tok::identifier); return Data->replaceChild(NewLocalName, Cursor::LocalName); } RC FunctionParameterSyntax::getColonToken() const { return cast(getRaw()->getChild(Cursor::Colon)); } FunctionParameterSyntax FunctionParameterSyntax:: withColonToken(RC NewColonToken) const { syntax_assert_token_is(NewColonToken, tok::colon, ":"); return Data->replaceChild(NewColonToken, Cursor::Colon); } llvm::Optional FunctionParameterSyntax::getTypeSyntax() const { auto RawType = getRaw()->getChild(Cursor::Type); if (RawType->isMissing()) { return llvm::None; } auto *MyData = getUnsafeData(); if (MyData->CachedTypeSyntax) { return TypeSyntax { Root, MyData->CachedTypeSyntax.get() }; } auto &ChildPtr = *reinterpret_cast*>( &MyData->CachedTypeSyntax); SyntaxData::realizeSyntaxNode(ChildPtr, RawType, MyData, cursorIndex(Cursor::Type)); return TypeSyntax { Root, MyData->CachedTypeSyntax.get() }; } FunctionParameterSyntax FunctionParameterSyntax:: withTypeSyntax(llvm::Optional NewType) const { if (!NewType.hasValue()) { auto RawType = RawSyntax::missing(SyntaxKind::MissingType); return Data->replaceChild(RawType, Cursor::Type); } return Data->replaceChild( NewType.getValue().getRaw(), Cursor::Type); } RC FunctionParameterSyntax::getEqualToken() const { return cast(getRaw()->getChild(Cursor::DefaultEqual)); } FunctionParameterSyntax FunctionParameterSyntax:: withEqualToken(RC NewEqualToken) const { assert(NewEqualToken->getTokenKind() == tok::equal); return Data->replaceChild(NewEqualToken, Cursor::DefaultEqual); } llvm::Optional FunctionParameterSyntax::getDefaultValue() const { auto RawExpr = getRaw()->getChild(Cursor::DefaultExpression); if (RawExpr->isMissing()) { return llvm::None; } auto *MyData = getUnsafeData(); if (MyData->CachedTypeSyntax) { return ExprSyntax { Root, MyData->CachedDefaultValue.get() }; } auto &ChildPtr = *reinterpret_cast*>( &MyData->CachedDefaultValue); SyntaxData::realizeSyntaxNode(ChildPtr, RawExpr, MyData, cursorIndex(Cursor::DefaultExpression)); return ExprSyntax { Root, MyData->CachedDefaultValue.get() }; } FunctionParameterSyntax FunctionParameterSyntax:: withDefaultValue(llvm::Optional NewDefaultValue) const { if (!NewDefaultValue.hasValue()) { auto RawType = RawSyntax::missing(SyntaxKind::MissingExpr); return Data->replaceChild(RawType, Cursor::DefaultExpression); } return Data->replaceChild( NewDefaultValue.getValue().getRaw(), Cursor::DefaultExpression); } RC FunctionParameterSyntax::getTrailingComma() const { return cast(getRaw()->getChild(Cursor::TrailingComma)); } FunctionParameterSyntax FunctionParameterSyntax:: withTrailingComma(RC NewTrailingComma) const { syntax_assert_token_is(NewTrailingComma, tok::comma, ","); return Data->replaceChild(NewTrailingComma, Cursor::TrailingComma); }