mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
320 lines
11 KiB
C++
320 lines
11 KiB
C++
//===--- 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 <atomic>
|
|
|
|
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<SyntaxData>,
|
|
private llvm::TrailingObjects<SyntaxData, AtomicCache<SyntaxData>> {
|
|
friend TrailingObjects;
|
|
|
|
using RootDataPair = std::pair<RC<SyntaxData>, RC<SyntaxData>>;
|
|
|
|
/// The shared raw syntax representing this syntax data node.
|
|
const RC<RawSyntax> 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<AbsolutePosition> PositionCache;
|
|
|
|
size_t numTrailingObjects(OverloadToken<AtomicCache<SyntaxData>>) const {
|
|
return Raw->getNumChildren();
|
|
}
|
|
|
|
SyntaxData(RC<RawSyntax> Raw, const SyntaxData *Parent = nullptr,
|
|
CursorIndex IndexInParent = 0)
|
|
: Raw(Raw), Parent(Parent), IndexInParent(IndexInParent) {
|
|
auto *I = getTrailingObjects<AtomicCache<SyntaxData>>();
|
|
for (auto *E = I + getNumChildren(); I != E; ++I)
|
|
::new (static_cast<void *>(I)) AtomicCache<SyntaxData>();
|
|
}
|
|
|
|
/// 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<RawSyntax> 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<SyntaxData> 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 <typename CursorType>
|
|
RootDataPair replaceChild(const RC<RawSyntax> RawChild,
|
|
CursorType ChildCursor) const {
|
|
auto NewRaw = Raw->replaceChild(ChildCursor, RawChild);
|
|
return replaceSelf(NewRaw);
|
|
}
|
|
|
|
ArrayRef<AtomicCache<SyntaxData>> getChildren() const {
|
|
return {getTrailingObjects<AtomicCache<SyntaxData>>(), getNumChildren()};
|
|
}
|
|
|
|
public:
|
|
/// Get the node immediately before this current node. Return 0 if we cannot
|
|
/// find such node.
|
|
RC<SyntaxData> getPreviousNode() const;
|
|
|
|
/// Get the node immediately after this current node. Return 0 if we cannot
|
|
/// find such node.
|
|
RC<SyntaxData> getNextNode() const;
|
|
|
|
/// Get the first token node in this tree
|
|
RC<SyntaxData> getFirstToken() const;
|
|
|
|
~SyntaxData() {
|
|
for (auto &I : getChildren())
|
|
I.~AtomicCache<SyntaxData>();
|
|
}
|
|
|
|
/// Constructs a SyntaxNode by replacing `self` and recursively building
|
|
/// the parent chain up to the root.
|
|
template <typename SyntaxNode>
|
|
SyntaxNode replaceSelf(const RC<RawSyntax> 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 <typename SyntaxNode, typename CursorType>
|
|
SyntaxNode replaceChild(const RC<RawSyntax> RawChild,
|
|
CursorType ChildCursor) const {
|
|
auto NewRootAndParent = replaceChild(RawChild, ChildCursor);
|
|
return SyntaxNode {
|
|
NewRootAndParent.first,
|
|
NewRootAndParent.second.get()
|
|
};
|
|
}
|
|
|
|
|
|
static RC<SyntaxData> make(RC<RawSyntax> Raw,
|
|
const SyntaxData *Parent = nullptr,
|
|
CursorIndex IndexInParent = 0);
|
|
|
|
/// Returns the raw syntax node for this syntax node.
|
|
const RC<RawSyntax> 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 <typename CursorType>
|
|
RC<SyntaxData> 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<RawSyntax> Raw = {
|
|
/// RC<RawTokenSyntax> { SyntaxKind::Token, tok::return_kw, "return" },
|
|
/// RC<RawSyntax> { SyntaxKind::SomeExpression, ... }
|
|
/// }
|
|
/// llvm::SmallVector<AtomicCache<SyntaxData>, 10> Children {
|
|
/// AtomicCache<SyntaxData> { RC<SyntaxData> = nullptr; },
|
|
/// AtomicCache<SyntaxData> { RC<SyntaxData> = 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<SyntaxData> 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<SyntaxData>, used for a Syntax Node -> lib/AST mapping.
|
|
namespace llvm {
|
|
using SD = swift::syntax::SyntaxData;
|
|
using RCSD = swift::RC<SD>;
|
|
template <> struct llvm::DenseMapInfo<RCSD> {
|
|
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<uintptr_t>::getHashValue(reinterpret_cast<const uintptr_t>(Value->getRaw().get()));
|
|
H ^= DenseMapInfo<uintptr_t>::getHashValue(reinterpret_cast<const uintptr_t>(Value->getParent()));
|
|
H ^= DenseMapInfo<swift::syntax::CursorIndex>::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
|