| //===--- AST.h - Markup AST nodes -------------------------------*- 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_MARKUP_AST_H |
| #define SWIFT_MARKUP_AST_H |
| |
| #include "swift/Markup/LineList.h" |
| #include "llvm/ADT/Optional.h" |
| #include "llvm/ADT/SetVector.h" |
| #include "llvm/Support/ErrorHandling.h" |
| #include "llvm/Support/TrailingObjects.h" |
| |
| namespace swift { |
| namespace markup { |
| |
| class MarkupContext; |
| class MarkupASTNode; |
| class Paragraph; |
| class ParamField; |
| class ReturnsField; |
| class TagField; |
| class ThrowsField; |
| class LocalizationKeyField; |
| |
| /// The basic structure of a doc comment attached to a Swift |
| /// declaration. |
| struct CommentParts { |
| Optional<const Paragraph *> Brief; |
| ArrayRef<const MarkupASTNode *> BodyNodes; |
| ArrayRef<ParamField *> ParamFields; |
| Optional<const swift::markup::ReturnsField *> ReturnsField; |
| Optional<const swift::markup::ThrowsField *> ThrowsField; |
| llvm::SmallSetVector<StringRef, 8> Tags; |
| Optional<const swift::markup::LocalizationKeyField *> LocalizationKeyField; |
| |
| bool isEmpty() const { |
| return !Brief.hasValue() && |
| !ReturnsField.hasValue() && |
| !ThrowsField.hasValue() && |
| BodyNodes.empty() && |
| ParamFields.empty(); |
| } |
| |
| bool hasFunctionDocumentation() const { |
| return !ParamFields.empty() || |
| ReturnsField.hasValue() || |
| ThrowsField.hasValue(); |
| } |
| }; |
| |
| #define MARKUP_AST_NODE(Id, Parent) class Id; |
| #define ABSTRACT_MARKUP_AST_NODE(Id, Parent) class Id; |
| #define MARKUP_AST_NODE_RANGE(Id, FirstId, LastId) |
| #include "swift/Markup/ASTNodes.def" |
| |
| enum class ASTNodeKind : uint8_t { |
| #define MARKUP_AST_NODE(Id, Parent) Id, |
| #define ABSTRACT_MARKUP_AST_NODE(Id, Parent) |
| #define MARKUP_AST_NODE_RANGE(Id, FirstId, LastId) \ |
| First_##Id = FirstId, Last_##Id = LastId, |
| #include "swift/Markup/ASTNodes.def" |
| }; |
| |
| class alignas(void *) MarkupASTNode { |
| MarkupASTNode(const MarkupASTNode &) = delete; |
| void operator=(const MarkupASTNode &) = delete; |
| |
| protected: |
| ASTNodeKind Kind; |
| |
| public: |
| |
| MarkupASTNode(ASTNodeKind Kind) : Kind(Kind) {} |
| |
| ASTNodeKind getKind() const { return Kind; } |
| |
| void *operator new(size_t Bytes, MarkupContext &MC, |
| unsigned alignment = alignof(MarkupASTNode)); |
| void *operator new(size_t Bytes, void *Mem) { |
| assert(Mem); |
| return Mem; |
| } |
| |
| ArrayRef<MarkupASTNode *> getChildren(); |
| ArrayRef<const MarkupASTNode *> getChildren() const; |
| void *operator new(size_t Bytes) = delete; |
| void operator delete(void *Data) = delete; |
| }; |
| |
| #pragma mark Markdown Nodes |
| |
| class Document final : public MarkupASTNode, |
| private llvm::TrailingObjects<Document, MarkupASTNode *> { |
| friend TrailingObjects; |
| |
| size_t NumChildren; |
| |
| Document(ArrayRef<MarkupASTNode*> Children); |
| |
| public: |
| static Document *create(MarkupContext &MC, |
| ArrayRef<MarkupASTNode *> Children); |
| |
| ArrayRef<MarkupASTNode *> getChildren() { |
| return {getTrailingObjects<MarkupASTNode *>(), NumChildren}; |
| } |
| |
| ArrayRef<const MarkupASTNode *> getChildren() const { |
| return {getTrailingObjects<MarkupASTNode *>(), NumChildren}; |
| } |
| |
| static bool classof(const MarkupASTNode *N) { |
| return N->getKind() == ASTNodeKind::Document; |
| } |
| }; |
| |
| class BlockQuote final : public MarkupASTNode, |
| private llvm::TrailingObjects<BlockQuote, MarkupASTNode *> { |
| friend TrailingObjects; |
| |
| size_t NumChildren; |
| |
| BlockQuote(ArrayRef<MarkupASTNode *> Children); |
| |
| public: |
| static BlockQuote *create(MarkupContext &MC, ArrayRef<MarkupASTNode *> Children); |
| |
| ArrayRef<MarkupASTNode *> getChildren() { |
| return {getTrailingObjects<MarkupASTNode *>(), NumChildren}; |
| } |
| |
| ArrayRef<const MarkupASTNode *> getChildren() const { |
| return {getTrailingObjects<MarkupASTNode *>(), NumChildren}; |
| } |
| |
| static bool classof(const MarkupASTNode *N) { |
| return N->getKind() == ASTNodeKind::BlockQuote; |
| } |
| }; |
| |
| class List final : public MarkupASTNode, |
| private llvm::TrailingObjects<List, MarkupASTNode *> { |
| friend TrailingObjects; |
| |
| size_t NumChildren; |
| bool Ordered; |
| |
| List(ArrayRef<MarkupASTNode *> Children, bool IsOrdered); |
| |
| public: |
| static List *create(MarkupContext &MC, ArrayRef<MarkupASTNode *> Items, |
| bool IsOrdered); |
| |
| ArrayRef<MarkupASTNode *> getChildren() { |
| return {getTrailingObjects<MarkupASTNode *>(), NumChildren}; |
| } |
| |
| ArrayRef<const MarkupASTNode *> getChildren() const { |
| return {getTrailingObjects<MarkupASTNode *>(), NumChildren}; |
| } |
| |
| void setChildren(ArrayRef<MarkupASTNode *> NewChildren) { |
| assert(NewChildren.size() <= NumChildren); |
| std::copy(NewChildren.begin(), NewChildren.end(), |
| getTrailingObjects<MarkupASTNode *>()); |
| NumChildren = NewChildren.size(); |
| } |
| |
| bool isOrdered() const { |
| return Ordered; |
| } |
| |
| static bool classof(const MarkupASTNode *N) { |
| return N->getKind() == ASTNodeKind::List; |
| } |
| }; |
| |
| class Item final : public MarkupASTNode, |
| private llvm::TrailingObjects<Item, MarkupASTNode *> { |
| friend TrailingObjects; |
| |
| size_t NumChildren; |
| |
| Item(ArrayRef<MarkupASTNode *> Children); |
| |
| public: |
| static Item *create(MarkupContext &MC, ArrayRef<MarkupASTNode *> Children); |
| |
| ArrayRef<MarkupASTNode *> getChildren() { |
| return {getTrailingObjects<MarkupASTNode *>(), NumChildren}; |
| } |
| |
| ArrayRef<const MarkupASTNode *> getChildren() const { |
| return {getTrailingObjects<MarkupASTNode *>(), NumChildren}; |
| } |
| |
| static bool classof(const MarkupASTNode *N) { |
| return N->getKind() == ASTNodeKind::Item; |
| } |
| }; |
| |
| class CodeBlock final : public MarkupASTNode { |
| StringRef LiteralContent; |
| StringRef Language; |
| |
| CodeBlock(StringRef LiteralContent, StringRef Language) |
| : MarkupASTNode(ASTNodeKind::CodeBlock), |
| LiteralContent(LiteralContent), |
| Language(Language) {} |
| |
| public: |
| static CodeBlock *create(MarkupContext &MC, StringRef LiteralContent, |
| StringRef Language); |
| |
| StringRef getLiteralContent() const { return LiteralContent; }; |
| StringRef getLanguage() const { return Language; }; |
| |
| ArrayRef<const MarkupASTNode *> getChildren() const { |
| return {}; |
| } |
| |
| ArrayRef<MarkupASTNode *> getChildren() { |
| return {}; |
| } |
| |
| static bool classof(const MarkupASTNode *N) { |
| return N->getKind() == ASTNodeKind::CodeBlock; |
| } |
| }; |
| |
| class HTML final : public MarkupASTNode { |
| StringRef LiteralContent; |
| HTML(StringRef LiteralContent) |
| : MarkupASTNode(ASTNodeKind::HTML), |
| LiteralContent(LiteralContent) {} |
| public: |
| static HTML *create(MarkupContext &MC, StringRef LiteralContent); |
| StringRef getLiteralContent() const { return LiteralContent; }; |
| |
| static bool classof(const MarkupASTNode *N) { |
| return N->getKind() == ASTNodeKind::HTML; |
| } |
| }; |
| |
| class Paragraph final : public MarkupASTNode, |
| private llvm::TrailingObjects<Paragraph, MarkupASTNode *> { |
| friend TrailingObjects; |
| |
| size_t NumChildren; |
| |
| Paragraph(ArrayRef<MarkupASTNode *> Children); |
| |
| public: |
| static Paragraph *create(MarkupContext &MC, |
| ArrayRef<MarkupASTNode *> Children); |
| |
| ArrayRef<MarkupASTNode *> getChildren() { |
| return {getTrailingObjects<MarkupASTNode *>(), NumChildren}; |
| } |
| |
| ArrayRef<const MarkupASTNode *> getChildren() const { |
| return {getTrailingObjects<MarkupASTNode *>(), NumChildren}; |
| } |
| |
| static bool classof(const MarkupASTNode *N) { |
| return N->getKind() == ASTNodeKind::Paragraph; |
| } |
| }; |
| |
| class Header final : public MarkupASTNode, |
| private llvm::TrailingObjects<Header, MarkupASTNode *> { |
| friend TrailingObjects; |
| |
| size_t NumChildren; |
| unsigned Level; |
| |
| Header(unsigned Level, ArrayRef<MarkupASTNode *> Children); |
| |
| public: |
| static Header *create(MarkupContext &MC, unsigned Level, |
| ArrayRef<MarkupASTNode *> Children); |
| |
| ArrayRef<MarkupASTNode *> getChildren() { |
| return {getTrailingObjects<MarkupASTNode *>(), NumChildren}; |
| } |
| |
| ArrayRef<const MarkupASTNode *> getChildren() const { |
| return {getTrailingObjects<MarkupASTNode *>(), NumChildren}; |
| } |
| |
| unsigned getLevel() const { |
| return Level; |
| } |
| static bool classof(const MarkupASTNode *N) { |
| return N->getKind() == ASTNodeKind::Header; |
| } |
| }; |
| |
| class HRule final : public MarkupASTNode { |
| HRule() : MarkupASTNode(ASTNodeKind::HRule) {} |
| public: |
| static HRule *create(MarkupContext &MC); |
| |
| ArrayRef<const MarkupASTNode *> getChildren() const { |
| return {}; |
| } |
| |
| ArrayRef<MarkupASTNode *> getChildren() { |
| return {}; |
| } |
| |
| static bool classof(const MarkupASTNode *N) { |
| return N->getKind() == ASTNodeKind::HRule; |
| } |
| }; |
| |
| class InlineContent : public MarkupASTNode { |
| public: |
| InlineContent(ASTNodeKind Kind) : MarkupASTNode(Kind) {} |
| |
| ArrayRef<const MarkupASTNode *> getChildren() const { |
| return {}; |
| } |
| |
| ArrayRef<MarkupASTNode *> getChildren() { |
| return {}; |
| } |
| |
| static bool classof(const MarkupASTNode *N) { |
| return N->getKind() >= ASTNodeKind::First_Inline && |
| N->getKind() <= ASTNodeKind::Last_Inline; |
| } |
| }; |
| |
| class Text final : public InlineContent { |
| StringRef LiteralContent; |
| Text(StringRef LiteralContent) |
| : InlineContent(ASTNodeKind::Text), |
| LiteralContent(LiteralContent) {} |
| public: |
| static Text *create(MarkupContext &MC, StringRef LiteralContent); |
| StringRef getLiteralContent() const { return LiteralContent; }; |
| void setLiteralContent(StringRef LC) { |
| LiteralContent = LC; |
| } |
| |
| ArrayRef<const MarkupASTNode *> getChildren() const { |
| return {}; |
| } |
| |
| ArrayRef<MarkupASTNode *> getChildren() { |
| return {}; |
| } |
| |
| StringRef str() const { |
| return LiteralContent; |
| } |
| |
| static bool classof(const MarkupASTNode *N) { |
| return N->getKind() == ASTNodeKind::Text; |
| } |
| }; |
| |
| class SoftBreak final : public InlineContent { |
| SoftBreak() : InlineContent(ASTNodeKind::SoftBreak) {} |
| public: |
| static SoftBreak *create(MarkupContext &MC); |
| |
| ArrayRef<const MarkupASTNode *> getChildren() const { |
| return {}; |
| } |
| |
| ArrayRef<MarkupASTNode *> getChildren() { |
| return {}; |
| } |
| |
| StringRef str() const { |
| return "\n"; |
| } |
| |
| static bool classof(const MarkupASTNode *N) { |
| return N->getKind() == ASTNodeKind::SoftBreak; |
| } |
| }; |
| |
| class LineBreak final : public InlineContent { |
| LineBreak() : InlineContent(ASTNodeKind::LineBreak) {} |
| public: |
| static LineBreak *create(MarkupContext &MC); |
| |
| ArrayRef<const MarkupASTNode *> getChildren() const { |
| return {}; |
| } |
| |
| ArrayRef<MarkupASTNode *> getChildren() { |
| return {}; |
| } |
| |
| StringRef str() const { |
| return "\n"; |
| } |
| |
| static bool classof(const MarkupASTNode *N) { |
| return N->getKind() == ASTNodeKind::LineBreak; |
| } |
| }; |
| |
| class Code final : public InlineContent { |
| StringRef LiteralContent; |
| |
| Code(StringRef LiteralContent) |
| : InlineContent(ASTNodeKind::Code), |
| LiteralContent(LiteralContent) {} |
| public: |
| static Code *create(MarkupContext &MC, StringRef LiteralContent); |
| |
| StringRef getLiteralContent() const { return LiteralContent; }; |
| |
| ArrayRef<const MarkupASTNode *> getChildren() const { |
| return {}; |
| } |
| |
| ArrayRef<MarkupASTNode *> getChildren() { |
| return {}; |
| } |
| |
| StringRef str() const { |
| return LiteralContent; |
| } |
| |
| static bool classof(const MarkupASTNode *N) { |
| return N->getKind() == ASTNodeKind::Code; |
| } |
| }; |
| |
| class InlineHTML final : public InlineContent { |
| StringRef LiteralContent; |
| InlineHTML(StringRef LiteralContent) |
| : InlineContent(ASTNodeKind::InlineHTML), |
| LiteralContent(LiteralContent) {} |
| public: |
| static InlineHTML *create(MarkupContext &MC, StringRef LiteralContent); |
| |
| StringRef getLiteralContent() const { return LiteralContent; }; |
| |
| ArrayRef<const MarkupASTNode *> getChildren() const { |
| return {}; |
| } |
| |
| ArrayRef<MarkupASTNode *> getChildren() { |
| return {}; |
| } |
| |
| StringRef str() const { |
| return LiteralContent; |
| } |
| |
| static bool classof(const MarkupASTNode *N) { |
| return N->getKind() == ASTNodeKind::InlineHTML; |
| } |
| }; |
| |
| class Emphasis final : public InlineContent, |
| private llvm::TrailingObjects<Emphasis, MarkupASTNode *> { |
| friend TrailingObjects; |
| |
| size_t NumChildren; |
| |
| Emphasis(ArrayRef<MarkupASTNode *> Children); |
| public: |
| static Emphasis *create(MarkupContext &MC, |
| ArrayRef<MarkupASTNode *> Children); |
| |
| ArrayRef<MarkupASTNode *> getChildren() { |
| return {getTrailingObjects<MarkupASTNode *>(), NumChildren}; |
| } |
| |
| ArrayRef<const MarkupASTNode *> getChildren() const { |
| return {getTrailingObjects<MarkupASTNode *>(), NumChildren}; |
| } |
| |
| static bool classof(const MarkupASTNode *N) { |
| return N->getKind() == ASTNodeKind::Emphasis; |
| } |
| }; |
| |
| class Strong final : public InlineContent, |
| private llvm::TrailingObjects<Strong, MarkupASTNode *> { |
| friend TrailingObjects; |
| |
| size_t NumChildren; |
| |
| Strong(ArrayRef<MarkupASTNode *> Children); |
| public: |
| static Strong *create(MarkupContext &MC, |
| ArrayRef<MarkupASTNode *> Children); |
| |
| ArrayRef<MarkupASTNode *> getChildren() { |
| return {getTrailingObjects<MarkupASTNode *>(), NumChildren}; |
| } |
| |
| ArrayRef<const MarkupASTNode *> getChildren() const { |
| return {getTrailingObjects<MarkupASTNode *>(), NumChildren}; |
| } |
| |
| static bool classof(const MarkupASTNode *N) { |
| return N->getKind() == ASTNodeKind::Strong; |
| } |
| }; |
| |
| class Link final : public InlineContent, |
| private llvm::TrailingObjects<Link, MarkupASTNode *> { |
| friend TrailingObjects; |
| |
| size_t NumChildren; |
| |
| StringRef Destination; |
| |
| Link(StringRef Destination, ArrayRef<MarkupASTNode *> Children); |
| |
| public: |
| static Link *create(MarkupContext &MC, |
| StringRef Destination, |
| ArrayRef<MarkupASTNode *> Children); |
| |
| StringRef getDestination() const { return Destination; } |
| |
| ArrayRef<MarkupASTNode *> getChildren() { |
| return {getTrailingObjects<MarkupASTNode *>(), NumChildren}; |
| } |
| |
| ArrayRef<const MarkupASTNode *> getChildren() const { |
| return {getTrailingObjects<MarkupASTNode *>(), NumChildren}; |
| } |
| |
| static bool classof(const MarkupASTNode *N) { |
| return N->getKind() == ASTNodeKind::Link; |
| } |
| }; |
| |
| class Image final : public InlineContent, |
| private llvm::TrailingObjects<Image, MarkupASTNode *> { |
| friend TrailingObjects; |
| |
| size_t NumChildren; |
| |
| // FIXME: Hyperlink destinations can't be wrapped - use a Line |
| StringRef Destination; |
| Optional<StringRef> Title; |
| |
| Image(StringRef Destination, Optional<StringRef> Title, |
| ArrayRef<MarkupASTNode *> Children); |
| |
| public: |
| static Image *create(MarkupContext &MC, |
| StringRef Destination, |
| Optional<StringRef> Title, |
| ArrayRef<MarkupASTNode *> Children); |
| |
| StringRef getDestination() const { return Destination; } |
| |
| bool hasTitle() const { |
| return Title.hasValue(); |
| } |
| |
| StringRef getTitle() const { |
| return StringRef(Title.getValue()); |
| } |
| |
| ArrayRef<MarkupASTNode *> getChildren() { |
| return {getTrailingObjects<MarkupASTNode *>(), NumChildren}; |
| } |
| |
| ArrayRef<const MarkupASTNode *> getChildren() const { |
| return {getTrailingObjects<MarkupASTNode *>(), NumChildren}; |
| } |
| |
| static bool classof(const MarkupASTNode *N) { |
| return N->getKind() == ASTNodeKind::Image; |
| } |
| }; |
| |
| #pragma mark Private Extensions |
| |
| class PrivateExtension : public MarkupASTNode { |
| protected: |
| PrivateExtension(ASTNodeKind Kind) |
| : MarkupASTNode(Kind) {} |
| public: |
| |
| ArrayRef<const MarkupASTNode *> getChildren() const { |
| return {}; |
| } |
| |
| ArrayRef<MarkupASTNode *> getChildren() { |
| return {}; |
| } |
| |
| static bool classof(const MarkupASTNode *N) { |
| return N->getKind() >= ASTNodeKind::First_Private && |
| N->getKind() <= ASTNodeKind::Last_Private; |
| } |
| }; |
| |
| class ParamField final : public PrivateExtension, |
| private llvm::TrailingObjects<ParamField, MarkupASTNode *> { |
| friend TrailingObjects; |
| |
| size_t NumChildren; |
| |
| StringRef Name; |
| |
| // Parameter fields can contain a substructure describing a |
| // function or closure parameter. |
| llvm::Optional<CommentParts> Parts; |
| |
| ParamField(StringRef Name, ArrayRef<MarkupASTNode *> Children); |
| |
| public: |
| |
| static ParamField *create(MarkupContext &MC, StringRef Name, |
| ArrayRef<MarkupASTNode *> Children); |
| |
| StringRef getName() const { |
| return Name; |
| } |
| |
| llvm::Optional<CommentParts> getParts() const { |
| return Parts; |
| } |
| |
| void setParts(CommentParts P) { |
| Parts = P; |
| } |
| |
| bool isClosureParameter() const { |
| if (!Parts.hasValue()) |
| return false; |
| |
| return Parts.getValue().hasFunctionDocumentation(); |
| } |
| |
| ArrayRef<MarkupASTNode *> getChildren() { |
| return {getTrailingObjects<MarkupASTNode *>(), NumChildren}; |
| } |
| |
| ArrayRef<const MarkupASTNode *> getChildren() const { |
| return {getTrailingObjects<MarkupASTNode *>(), NumChildren}; |
| } |
| |
| static bool classof(const MarkupASTNode *N) { |
| return N->getKind() == ASTNodeKind::ParamField; |
| } |
| }; |
| |
| #define MARKUP_SIMPLE_FIELD(Id, Keyword, XMLKind) \ |
| class Id final : public PrivateExtension, \ |
| private llvm::TrailingObjects<Id, MarkupASTNode *> { \ |
| friend TrailingObjects; \ |
| \ |
| size_t NumChildren; \ |
| \ |
| Id(ArrayRef<MarkupASTNode *> Children);\ |
| \ |
| public: \ |
| static Id *create(MarkupContext &MC, ArrayRef<MarkupASTNode *> Children); \ |
| \ |
| ArrayRef<MarkupASTNode *> getChildren() { \ |
| return {getTrailingObjects<MarkupASTNode *>(), NumChildren}; \ |
| } \ |
| \ |
| ArrayRef<const MarkupASTNode *> getChildren() const { \ |
| return {getTrailingObjects<MarkupASTNode *>(), NumChildren}; \ |
| } \ |
| \ |
| static bool classof(const MarkupASTNode *N) { \ |
| return N->getKind() == ASTNodeKind::Id; \ |
| } \ |
| }; |
| #include "swift/Markup/SimpleFields.def" |
| |
| class MarkupASTWalker { |
| public: |
| void walk(const MarkupASTNode *Node) { |
| enter(Node); |
| |
| switch(Node->getKind()) { |
| #define MARKUP_AST_NODE(Id, Parent) \ |
| case ASTNodeKind::Id: \ |
| visit##Id(static_cast<const Id*>(Node)); \ |
| break; |
| #define ABSTRACT_MARKUP_AST_NODE(Id, Parent) |
| #define MARKUP_AST_NODE_RANGE(Id, FirstId, LastId) |
| #include "swift/Markup/ASTNodes.def" |
| } |
| |
| if (shouldVisitChildrenOf(Node)) |
| for (auto Child : Node->getChildren()) |
| walk(Child); |
| |
| exit(Node); |
| } |
| |
| virtual bool shouldVisitChildrenOf(const MarkupASTNode *Node) { |
| return true; |
| } |
| |
| virtual void enter(const MarkupASTNode *Node) {} |
| virtual void exit(const MarkupASTNode *Node) {} |
| |
| #define MARKUP_AST_NODE(Id, Parent) \ |
| virtual void visit##Id(const Id *Node) {} |
| #define ABSTRACT_MARKUP_AST_NODE(Id, Parent) |
| #define MARKUP_AST_NODE_RANGE(Id, FirstId, LastId) |
| #include "swift/Markup/ASTNodes.def" |
| |
| virtual ~MarkupASTWalker() = default; |
| }; |
| |
| MarkupASTNode *createSimpleField(MarkupContext &MC, StringRef Tag, |
| ArrayRef<MarkupASTNode *> Children); |
| |
| bool isAFieldTag(StringRef Tag); |
| |
| void dump(const MarkupASTNode *Node, llvm::raw_ostream &OS, unsigned indent = 0); |
| void printInlinesUnder(const MarkupASTNode *Node, llvm::raw_ostream &OS, |
| bool PrintDecorators = false); |
| |
| |
| template <typename ImplClass, typename RetTy = void, typename... Args> |
| class MarkupASTVisitor { |
| public: |
| RetTy visit(const MarkupASTNode *Node, Args... args) { |
| switch (Node->getKind()) { |
| #define MARKUP_AST_NODE(Id, Parent) \ |
| case ASTNodeKind::Id: \ |
| return static_cast<ImplClass*>(this) \ |
| ->visit##Id(cast<const Id>(Node), \ |
| ::std::forward<Args>(args)...); |
| #define ABSTRACT_MARKUP_AST_NODE(Id, Parent) |
| #define MARKUP_AST_NODE_RANGE(Id, FirstId, LastId) |
| #include "swift/Markup/ASTNodes.def" |
| } |
| } |
| |
| virtual ~MarkupASTVisitor() {} |
| }; |
| |
| } // namespace markup |
| } // namespace swift |
| |
| #endif // SWIFT_MARKUP_AST_H |