//===--- SyntaxData.h - Swift Syntax Data Interface -------------*- 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 // //===----------------------------------------------------------------------===// // // This file defines the SyntaxData interface, the type for the instance // data for Syntax nodes. // // Effectively, these provide two main things to a Syntax node - parental // relationships and caching for its children. // // A SyntaxData contains at least a strong reference to the RawSyntax, // from which most information comes, and additionally a weak reference to // its parent and the "index" at which it occurs in its parent. These were // originally intended to have the important public APIs for structured // editing but now contain no significant or public API; for those, see the // Syntax type. These are purely to contain data, hence the name. // // Conceptually, SyntaxData add the characteristic of specific identity in a // piece of Swift source code. While the RawSyntax for the integer literal // token '1' can be reused anywhere a '1' occurs and has identical formatting, // a SyntaxData represents *a* specific '1' at a particular location in // Swift source. // // These are effectively internal implementation. For all public APIs, look // for the type without "Data" in its name. For example, a StructDeclSyntaxData // expresses its API through the wrapping StructDeclSyntax type. // //===----------------------------------------------------------------------===// #ifndef SWIFT_SYNTAX_SYNTAXDATA_H #define SWIFT_SYNTAX_SYNTAXDATA_H #include "swift/Syntax/AtomicCache.h" #include "swift/Syntax/RawSyntax.h" #include "swift/Syntax/References.h" #include "llvm/ADT/DenseMap.h" #include namespace swift { namespace syntax { /// The class for holding parented syntax. /// /// This structure should not contain significant public /// API or internal modification API. /// /// This is only for holding a strong reference to the RawSyntax, a weak /// reference to the parent, and, in subclasses, lazily created strong /// references to non-terminal child nodes. class SyntaxData final : public llvm::ThreadSafeRefCountedBase, private llvm::TrailingObjects> { friend TrailingObjects; using RootDataPair = std::pair, RC>; /// The shared raw syntax representing this syntax data node. const RC Raw; /// The parent of this syntax. /// /// WARNING! Do not access this directly. Use getParent(), /// which enforces nullptr checking. const SyntaxData *Parent; /// The index into the parent's child layout. /// /// If there is no parent, this is 0. const CursorIndex IndexInParent; /// Cache the absolute position of this node. Optional PositionCache; size_t numTrailingObjects(OverloadToken>) const { return Raw->getNumChildren(); } SyntaxData(RC Raw, const SyntaxData *Parent = nullptr, CursorIndex IndexInParent = 0) : Raw(Raw), Parent(Parent), IndexInParent(IndexInParent) { auto *I = getTrailingObjects>(); for (auto *E = I + getNumChildren(); I != E; ++I) ::new (static_cast(I)) AtomicCache(); } /// With a new RawSyntax node, create a new node from this one and /// recursively rebuild the parental chain up to the root. /// /// DO NOT expose this as public API. RootDataPair replaceSelf(const RC NewRaw) const { if (hasParent()) { auto NewRootAndParent = Parent->replaceChild(NewRaw, IndexInParent); auto NewMe = NewRootAndParent.second->getChild(IndexInParent); return { NewRootAndParent.first, NewMe.get() }; } else { auto NewMe = make(NewRaw, nullptr, IndexInParent); return { NewMe, NewMe.get() }; } } /// Create the data for a child node with the raw syntax in our layout /// at the provided index. /// DO NOT expose this as public API. RC realizeSyntaxNode(CursorIndex Index) const { if (auto &RawChild = Raw->getChild(Index)) return SyntaxData::make(RawChild, this, Index); return nullptr; } /// Replace a child in the raw syntax and recursively rebuild the /// parental chain up to the root. /// /// DO NOT expose this as public API. template RootDataPair replaceChild(const RC RawChild, CursorType ChildCursor) const { auto NewRaw = Raw->replaceChild(ChildCursor, RawChild); return replaceSelf(NewRaw); } ArrayRef> getChildren() const { return {getTrailingObjects>(), getNumChildren()}; } public: /// Get the node immediately before this current node. Return 0 if we cannot /// find such node. RC getPreviousNode() const; /// Get the node immediately after this current node. Return 0 if we cannot /// find such node. RC getNextNode() const; /// Get the first token node in this tree RC getFirstToken() const; ~SyntaxData() { for (auto &I : getChildren()) I.~AtomicCache(); } /// Constructs a SyntaxNode by replacing `self` and recursively building /// the parent chain up to the root. template SyntaxNode replaceSelf(const RC NewRaw) const { auto NewRootAndData = replaceSelf(NewRaw); return { NewRootAndData.first, NewRootAndData.second.get() }; } /// Replace a child in the raw syntax and recursively rebuild the /// parental chain up to the root. /// /// DO NOT expose this as public API. template SyntaxNode replaceChild(const RC RawChild, CursorType ChildCursor) const { auto NewRootAndParent = replaceChild(RawChild, ChildCursor); return SyntaxNode { NewRootAndParent.first, NewRootAndParent.second.get() }; } static RC make(RC Raw, const SyntaxData *Parent = nullptr, CursorIndex IndexInParent = 0); /// Returns the raw syntax node for this syntax node. const RC getRaw() const { return Raw; } /// Returns the kind of syntax node this is. SyntaxKind getKind() const { return Raw->getKind(); } /// Return the parent syntax if there is one. const SyntaxData * getParent() const { return Parent; } /// Returns true if this syntax node has a parent. bool hasParent() const { return Parent != nullptr; } /// Returns the child index of this node in its parent, if it has a parent, /// otherwise 0. size_t getIndexInParent() const { return IndexInParent; } /// Returns the number of children this SyntaxData represents. size_t getNumChildren() const { return Raw->getLayout().size(); } /// Gets the child at the index specified by the provided cursor, /// lazily creating it if necessary. template RC getChild(CursorType Cursor) const { return getChild((size_t)cursorIndex(Cursor)); } /// Gets the child at the specified index in this data's children array. /// Why do we need this? /// - SyntaxData nodes should have pointer identity. /// - We only want to construct parented, realized child nodes as /// SyntaxData when asked. /// /// For example, if we have a ReturnStmtSyntax, and ask for its returned /// expression for the first time with getExpression(), two nodes can race /// to create and set the cached expression. /// /// Looking at an example - say we have a SyntaxData. /// /// SyntaxData = { /// RC Raw = { /// RC { SyntaxKind::Token, tok::return_kw, "return" }, /// RC { SyntaxKind::SomeExpression, ... } /// } /// llvm::SmallVector, 10> Children { /// AtomicCache { RC = nullptr; }, /// AtomicCache { RC = nullptr; }, /// } /// } /// /// If we wanted to safely create the 0th child, an instance of TokenSyntax, /// then we ask the AtomicCache in that position to realize its value and /// cache it. This is safe because AtomicCache only ever mutates its cache /// one time -- the first initialization that wins a compare_exchange_strong. RC getChild(size_t Index) const { if (!getRaw()->getChild(Index)) return nullptr; return getChildren()[Index].getOrCreate([&]() { return realizeSyntaxNode(Index); }); } /// Calculate the absolute position of this node, use cache if the cache /// is populated. AbsolutePosition getAbsolutePosition() const; /// Calculate the absolute end position of this node, use cache of the immediate /// next node if populated. AbsolutePosition getAbsoluteEndPosition() const; /// Get the absolute position without skipping the leading trivia of this /// node. AbsolutePosition getAbsolutePositionWithLeadingTrivia() const; /// Returns true if the data node represents type syntax. bool isType() const; /// Returns true if the data node represents statement syntax. bool isStmt() const; /// Returns true if the data node represents declaration syntax. bool isDecl() const; /// Returns true if the data node represents expression syntax. bool isExpr() const; /// Returns true if the data node represents pattern syntax. bool isPattern() const; /// Returns true if this syntax is of some "unknown" kind. bool isUnknown() const; /// Dump a debug description of the syntax data for debugging to /// standard error. void dump(llvm::raw_ostream &OS) const; LLVM_ATTRIBUTE_DEPRECATED(void dump() const LLVM_ATTRIBUTE_USED, "Only meant for use in the debugger"); }; } // end namespace syntax } // end namespace swift // DenseMapInfo for RC, used for a Syntax Node -> lib/AST mapping. namespace llvm { using SD = swift::syntax::SyntaxData; using RCSD = swift::RC; template <> struct llvm::DenseMapInfo { static inline RCSD getEmptyKey() { return SD::make(nullptr, nullptr, 0); } static inline RCSD getTombstoneKey() { return SD::make(nullptr, nullptr, 0); } static unsigned getHashValue(const RCSD Value) { unsigned H = 0; H ^= DenseMapInfo::getHashValue(reinterpret_cast(Value->getRaw().get())); H ^= DenseMapInfo::getHashValue(reinterpret_cast(Value->getParent())); H ^= DenseMapInfo::getHashValue(Value->getIndexInParent()); return H; } static bool isEqual(const RCSD LHS, const RCSD RHS) { return LHS->getRaw().get() == RHS->getRaw().get() && LHS->getParent() == RHS->getParent() && LHS->getIndexInParent() == RHS->getIndexInParent(); } }; } #endif // SWIFT_SYNTAX_SYNTAXDATA_H