//===--- SyntaxCollection.h -------------------------------------*- C++ -*-===// // // 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 // //===----------------------------------------------------------------------===// #ifndef SWIFT_SYNTAX_SYNTAXCOLLECTION_H #define SWIFT_SYNTAX_SYNTAXCOLLECTION_H #include "swift/Syntax/Syntax.h" #include namespace swift { namespace syntax { // MARK: - SyntaxCollection template class SyntaxCollection; template struct SyntaxCollectionIterator { const SyntaxCollection &Collection; size_t Index; Element operator*() { return Collection[Index]; } SyntaxCollectionIterator &operator++() { ++Index; return *this; } bool operator==(const SyntaxCollectionIterator &Other) { return Collection.hasSameIdentityAs(Other.Collection) && Index == Other.Index; } bool operator!=(const SyntaxCollectionIterator &Other) { return !operator==(Other); } }; /// A generic unbounded collection of syntax nodes template class SyntaxCollection : public Syntax { friend class Syntax; private: static RC makeData(std::initializer_list &Elements, const RC &Arena) { auto RawElements = llvm::map_iterator( Elements.begin(), [](const Element &Elt) -> const RawSyntax * { return Elt.getRaw(); }); auto Raw = RawSyntax::make(CollectionKind, RawElements, Elements.size(), SourcePresence::Present, Arena); return SyntaxData::makeRoot(AbsoluteRawSyntax::forRoot(Raw)); } public: SyntaxCollection(const RC &Data) : Syntax(Data) { validate(); } SyntaxCollection(std::initializer_list list): SyntaxCollection(SyntaxCollection::makeData(list)) {} void validate() {} /// Returns true if the collection is empty. bool empty() const { return size() == 0; } /// Returns the number of elements in the collection. size_t size() const { return getRaw()->getLayout().size(); } SyntaxCollectionIterator begin() const { return SyntaxCollectionIterator { *this, 0, }; } SyntaxCollectionIterator end() const { return SyntaxCollectionIterator { *this, getRaw()->getLayout().size(), }; } /// Return the element at the given Index. /// /// Precondition: Index < size() /// Precondition: !empty() Element operator[](const size_t Index) const { assert(Index < size()); assert(!empty()); return Element(Data->getChild(Index)); } /// Return a new collection with the given element added to the end. SyntaxCollection appending(Element E) const { auto OldLayout = getRaw()->getLayout(); std::vector NewLayout; NewLayout.reserve(OldLayout.size() + 1); std::copy(OldLayout.begin(), OldLayout.end(), back_inserter(NewLayout)); NewLayout.push_back(E.getRaw()); auto Raw = RawSyntax::make(CollectionKind, NewLayout, getRaw()->getPresence(), getRaw()->getArena()); return SyntaxCollection(Data->replacingSelf(Raw)); } /// Return a new collection with an element removed from the end. /// /// Precondition: !empty() SyntaxCollection removingLast() const { assert(!empty()); auto NewLayout = getRaw()->getLayout().drop_back(); auto Raw = RawSyntax::make(CollectionKind, NewLayout, getRaw()->getPresence(), getRaw()->getArena()); return SyntaxCollection(Data->replacingSelf(Raw)); } /// Return a new collection with the given element appended to the front. SyntaxCollection prepending(Element E) const { auto OldLayout = getRaw()->getLayout(); std::vector NewLayout = {E.getRaw()}; std::copy(OldLayout.begin(), OldLayout.end(), std::back_inserter(NewLayout)); auto Raw = RawSyntax::make(CollectionKind, NewLayout, getRaw()->getPresence(), getRaw()->getArena()); return SyntaxCollection(Data->replacingSelf(Raw)); } /// Return a new collection with an element removed from the end. /// /// Precondition: !empty() SyntaxCollection removingFirst() const { assert(!empty()); auto NewLayout = getRaw()->getLayout().drop_front(); auto Raw = RawSyntax::make(CollectionKind, NewLayout, getRaw()->getPresence(), getRaw()->getArena()); return SyntaxCollection(Data->replacingSelf(Raw)); } /// Return a new collection with the Element inserted at index i. /// /// Precondition: i <= size() SyntaxCollection inserting(size_t i, Element E) const { assert(i <= size()); auto OldLayout = getRaw()->getLayout(); std::vector NewLayout; NewLayout.reserve(OldLayout.size() + 1); std::copy(OldLayout.begin(), OldLayout.begin() + i, std::back_inserter(NewLayout)); NewLayout.push_back(E.getRaw()); std::copy(OldLayout.begin() + i, OldLayout.end(), std::back_inserter(NewLayout)); auto Raw = RawSyntax::make(CollectionKind, NewLayout, getRaw()->getPresence(), getRaw()->getArena()); return SyntaxCollection(Data->replacingSelf(Raw)); } /// Return a new collection with the element removed at index i. SyntaxCollection removing(size_t i) const { assert(i <= size()); std::vector NewLayout = getRaw()->getLayout(); auto iterator = NewLayout.begin(); std::advance(iterator, i); NewLayout.erase(iterator); auto Raw = RawSyntax::make(CollectionKind, NewLayout, getRaw()->getPresence(), getRaw()->getArena()); return SyntaxCollection(Data->replacingSelf(Raw)); } /// Return an empty syntax collection of this type. SyntaxCollection cleared() const { auto Raw = RawSyntax::make(CollectionKind, {}, getRaw()->getPresence(), getRaw()->getArena()); return SyntaxCollection(Data->replacingSelf(Raw)); } static bool kindof(SyntaxKind Kind) { return Kind == CollectionKind; } static bool classof(const Syntax *S) { return kindof(S->getKind()); } }; // MARK: - SyntaxCollectionRef template class SyntaxCollectionRef; template struct SyntaxCollectionRefIterator { const SyntaxCollectionRef &Collection; size_t Index; OwnedSyntaxRef operator*() { return Collection.getChild(Index); } SyntaxCollectionRefIterator &operator++() { ++Index; return *this; } bool operator==( const SyntaxCollectionRefIterator &Other) { return Collection.hasSameIdentityAs(Other.Collection) && Index == Other.Index; } bool operator!=( const SyntaxCollectionRefIterator &Other) { return !operator==(Other); } }; /// A generic unbounded collection of \c SyntaxRef nodes. template class SyntaxCollectionRef : public SyntaxRef { friend class Syntax; public: SyntaxCollectionRef(const SyntaxDataRef *Data) : SyntaxRef(Data) { validate(); } SyntaxCollectionRef(const SyntaxDataRef *Data, no_validation_t) : SyntaxRef(Data) {} void validate() {} /// Returns true if the collection is empty. bool empty() const { return size() == 0; } /// Returns the number of elements in the collection. size_t size() const { return getRaw()->getLayout().size(); } SyntaxCollectionRefIterator begin() const { return SyntaxCollectionRefIterator{ /*Collection=*/*this, /*Index=*/0, }; } SyntaxCollectionRefIterator end() const { return SyntaxCollectionRefIterator{ /*Collection=*/*this, /*Index=*/getRaw()->getLayout().size(), }; } /// Return the element at the given Index. /// /// Precondition: Index < size() OwnedSyntaxRef getChild(const size_t Index) const { assert(Index < size() && "Index out of bounds"); OwnedSyntaxRef Result; getDataRef()->getChildRef(Index, Result.getDataPtr()); return Result; } static bool kindof(SyntaxKind Kind) { return Kind == CollectionKind; } static bool classof(const SyntaxRef *S) { return kindof(S->getKind()); } }; } // end namespace syntax } // end namespace swift #endif // SWIFT_SYNTAX_SYNTAXCOLLECTION_H