//===--- AST.h - Markup AST nodes -------------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://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/Support/ErrorHandling.h" #include "llvm/Support/TrailingObjects.h" namespace swift { namespace markup { class MarkupContext; class MarkupASTNode; class Paragraph; class ParamField; class ReturnsField; class ThrowsField; /// The basic structure of a doc comment attached to a Swift /// declaration. struct CommentParts { Optional Brief; ArrayRef BodyNodes; ArrayRef ParamFields; Optional ReturnsField; Optional ThrowsField; 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 getChildren(); ArrayRef 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 { friend TrailingObjects; size_t NumChildren; Document(ArrayRef Children); public: static Document *create(MarkupContext &MC, ArrayRef Children); ArrayRef getChildren() { return {getTrailingObjects(), NumChildren}; } ArrayRef getChildren() const { return {getTrailingObjects(), NumChildren}; } static bool classof(const MarkupASTNode *N) { return N->getKind() == ASTNodeKind::Document; } }; class BlockQuote final : public MarkupASTNode, private llvm::TrailingObjects { friend TrailingObjects; size_t NumChildren; BlockQuote(ArrayRef Children); public: static BlockQuote *create(MarkupContext &MC, ArrayRef Children); ArrayRef getChildren() { return {getTrailingObjects(), NumChildren}; } ArrayRef getChildren() const { return {getTrailingObjects(), NumChildren}; } static bool classof(const MarkupASTNode *N) { return N->getKind() == ASTNodeKind::BlockQuote; } }; class List final : public MarkupASTNode, private llvm::TrailingObjects { friend TrailingObjects; size_t NumChildren; bool Ordered; List(ArrayRef Children, bool IsOrdered); public: static List *create(MarkupContext &MC, ArrayRef Items, bool IsOrdered); ArrayRef getChildren() { return {getTrailingObjects(), NumChildren}; } ArrayRef getChildren() const { return {getTrailingObjects(), NumChildren}; } void setChildren(ArrayRef NewChildren) { assert(NewChildren.size() <= NumChildren); std::copy(NewChildren.begin(), NewChildren.end(), getTrailingObjects()); 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 { friend TrailingObjects; size_t NumChildren; Item(ArrayRef Children); public: static Item *create(MarkupContext &MC, ArrayRef Children); ArrayRef getChildren() { return {getTrailingObjects(), NumChildren}; } ArrayRef getChildren() const { return {getTrailingObjects(), 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 getChildren() const { return {}; } ArrayRef 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 { friend TrailingObjects; size_t NumChildren; Paragraph(ArrayRef Children); public: static Paragraph *create(MarkupContext &MC, ArrayRef Children); ArrayRef getChildren() { return {getTrailingObjects(), NumChildren}; } ArrayRef getChildren() const { return {getTrailingObjects(), NumChildren}; } static bool classof(const MarkupASTNode *N) { return N->getKind() == ASTNodeKind::Paragraph; } }; class Header final : public MarkupASTNode, private llvm::TrailingObjects { friend TrailingObjects; size_t NumChildren; unsigned Level; Header(unsigned Level, ArrayRef Children); public: static Header *create(MarkupContext &MC, unsigned Level, ArrayRef Children); ArrayRef getChildren() { return {getTrailingObjects(), NumChildren}; } ArrayRef getChildren() const { return {getTrailingObjects(), 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 getChildren() const { return {}; } ArrayRef getChildren() { return {}; } static bool classof(const MarkupASTNode *N) { return N->getKind() == ASTNodeKind::HRule; } }; class InlineContent : public MarkupASTNode { public: InlineContent(ASTNodeKind Kind) : MarkupASTNode(Kind) {} ArrayRef getChildren() const { return {}; } ArrayRef 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 getChildren() const { return {}; } ArrayRef 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 getChildren() const { return {}; } ArrayRef 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 getChildren() const { return {}; } ArrayRef 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 getChildren() const { return {}; } ArrayRef 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 getChildren() const { return {}; } ArrayRef 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 { friend TrailingObjects; size_t NumChildren; Emphasis(ArrayRef Children); public: static Emphasis *create(MarkupContext &MC, ArrayRef Children); ArrayRef getChildren() { return {getTrailingObjects(), NumChildren}; } ArrayRef getChildren() const { return {getTrailingObjects(), NumChildren}; } static bool classof(const MarkupASTNode *N) { return N->getKind() == ASTNodeKind::Emphasis; } }; class Strong final : public InlineContent, private llvm::TrailingObjects { friend TrailingObjects; size_t NumChildren; Strong(ArrayRef Children); public: static Strong *create(MarkupContext &MC, ArrayRef Children); ArrayRef getChildren() { return {getTrailingObjects(), NumChildren}; } ArrayRef getChildren() const { return {getTrailingObjects(), NumChildren}; } static bool classof(const MarkupASTNode *N) { return N->getKind() == ASTNodeKind::Strong; } }; class Link final : public InlineContent, private llvm::TrailingObjects { friend TrailingObjects; size_t NumChildren; StringRef Destination; Link(StringRef Destination, ArrayRef Children); public: static Link *create(MarkupContext &MC, StringRef Destination, ArrayRef Children); StringRef getDestination() const { return Destination; } ArrayRef getChildren() { return {getTrailingObjects(), NumChildren}; } ArrayRef getChildren() const { return {getTrailingObjects(), NumChildren}; } static bool classof(const MarkupASTNode *N) { return N->getKind() == ASTNodeKind::Link; } }; class Image final : public InlineContent, private llvm::TrailingObjects { friend TrailingObjects; size_t NumChildren; // FIXME: Hyperlink destinations can't be wrapped - use a Line StringRef Destination; Optional Title; Image(StringRef Destination, Optional Title, ArrayRef Children); public: static Image *create(MarkupContext &MC, StringRef Destination, Optional Title, ArrayRef Children); StringRef getDestination() const { return Destination; } bool hasTitle() const { return Title.hasValue(); } StringRef getTitle() const { return StringRef(Title.getValue()); } ArrayRef getChildren() { return {getTrailingObjects(), NumChildren}; } ArrayRef getChildren() const { return {getTrailingObjects(), 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 getChildren() const { return {}; } ArrayRef 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 { friend TrailingObjects; size_t NumChildren; StringRef Name; // Parameter fields can contain a substructure describing a // function or closure parameter. llvm::Optional Parts; ParamField(StringRef Name, ArrayRef Children); public: static ParamField *create(MarkupContext &MC, StringRef Name, ArrayRef Children); StringRef getName() const { return Name; } llvm::Optional getParts() const { return Parts; } void setParts(CommentParts P) { Parts = P; } bool isClosureParameter() const { if (!Parts.hasValue()) return false; return Parts.getValue().hasFunctionDocumentation(); } ArrayRef getChildren() { return {getTrailingObjects(), NumChildren}; } ArrayRef getChildren() const { return {getTrailingObjects(), 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 { \ friend TrailingObjects; \ \ size_t NumChildren; \ \ Id(ArrayRef Children);\ \ public: \ static Id *create(MarkupContext &MC, ArrayRef Children); \ \ ArrayRef getChildren() { \ return {getTrailingObjects(), NumChildren}; \ } \ \ ArrayRef getChildren() const { \ return {getTrailingObjects(), 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(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 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); } // namespace markup } // namespace swift #endif // SWIFT_MARKUP_AST_H