//===--- 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 { 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) { std::vector List; List.reserve(Elements.size()); for (auto &Elt : Elements) List.push_back(Elt.getRaw()); auto Raw = RawSyntax::makeAndCalcLength(CollectionKind, List, SourcePresence::Present, Arena); return SyntaxData::makeRoot(AbsoluteRawSyntax::forRoot(Raw)); } public: SyntaxCollection(const RC &Data) : Syntax(Data) {} SyntaxCollection(std::initializer_list list): SyntaxCollection(SyntaxCollection::makeData(list)) {} /// 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::makeAndCalcLength(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::makeAndCalcLength(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::makeAndCalcLength(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::makeAndCalcLength(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::makeAndCalcLength(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::makeAndCalcLength(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::makeAndCalcLength( 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()); } }; } // end namespace syntax } // end namespace swift #endif // SWIFT_SYNTAX_SYNTAXCOLLECTION_H