//===--- 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 base 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 reprsents *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/RawSyntax.h" #include "swift/Syntax/References.h" #include "swift/Syntax/Syntax.h" #include "llvm/ADT/DenseMap.h" #include namespace swift { namespace syntax { class Syntax; /// The base class for holding parented syntax. /// /// This structure and subclasses thereof 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 : public llvm::ThreadSafeRefCountedBase { friend struct SyntaxFactory; #define SYNTAX(Id, Parent) friend class Id##Syntax; #include "swift/Syntax/SyntaxKinds.def" public: /// 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; protected: SyntaxData(RC Raw, const SyntaxData *Parent = nullptr, CursorIndex IndexInParent = 0) : Raw(Raw), Parent(Parent), IndexInParent(IndexInParent) {} /// 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. template SyntaxNode replaceSelf(RC NewRaw) const { auto NewMe = SyntaxNode::DataType::make(NewRaw, nullptr, IndexInParent); if (hasParent()) { auto NewRootAndParent = getParent().getValue() ->replaceChild(NewRaw, IndexInParent); NewMe->Parent = NewRootAndParent.Data; return SyntaxNode { NewRootAndParent.Root, cast(NewMe.get()) }; } else { return SyntaxNode { NewMe, cast(NewMe.get()) }; } } /// Unsafely instantiate a child within another node. /// /// DANGER! /// /// Scary thread-safe code here. This should only be used for internally /// mutating cached children! /// /// 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 ReturnStmtSyntaxData. /// /// ReturnStmtSyntaxData = { /// RC Raw = { /// RC { SyntaxKind::SomeExpression, ... } /// } /// RC CachedExpression = { 0 }; /// } /// /// We pretend that `CachedExpression` is a std::atomic &, so that /// we can safely instantiate that field using the RawSyntax for the /// expression, i.e. getRaw()->getChild(ReturnStmtSyntax::Cursor::Expression)) template static void realizeSyntaxNode(std::atomic &Child, RC RawChild, const SyntaxData *Parent, CursorIndex IndexInParent) { // We rely on the fact that an RC<___SyntaxData> is pointer-sized, which // means we can atomically compare-exchange the child field. // If we can't do that, we can't pretend it's a uintptr_t and use its // compare_exchange_strong. static_assert( sizeof(uintptr_t) == sizeof(RC), "Can't safely atomically replace a child SyntaxData node " "for caching! This is the end of the world!"); if (Child == 0) { // We expect the uncached value to wrap a nullptr. If another thread // beats us to caching the child, it'll be non-null, so we would // leave it alone. uintptr_t Expected = 0; // Make a RC at RefCount == 1, which we'll try to // atomically swap in. RC Data = cast( SyntaxData::makeDataFromRaw(RawChild, Parent, IndexInParent)); // Try to swap in raw pointer value. auto SuccessfullySwapped = Child.compare_exchange_strong(Expected, reinterpret_cast(Data.get())); // If we won, then leave the RefCount == 1. if (SuccessfullySwapped) { Data.resetWithoutRelease(); } // Otherwise, the Data we just made is unfortunately useless. // Let it die on this scope exit after its terminal release. } } /// Replace a child in the raw syntax and recursively rebuild the /// parental chain up to the rooet. /// /// This is the effective private implementation of all setters in /// subclasses of `SyntaxData`. /// /// DO NOT expose this as public API. template SyntaxNode replaceChild(RC RawChild, CursorType ChildCursor) const { auto NewRaw = Raw->replaceChild(ChildCursor, RawChild); return replaceSelf(NewRaw); } public: static RC makeDataFromRaw(RC Raw, const SyntaxData *Parent, CursorIndex IndexInParent); 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->Kind; } /// Return the parent syntax if there is one. llvm::Optional getParent() const { if (Parent != nullptr) { return Parent; } return NoParent; } /// 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 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 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; }; } // 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::syntax::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->Raw.get())); H ^= DenseMapInfo::getHashValue(reinterpret_cast(Value->Parent)); 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