Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions bindings/xml/comment-xml-schema.rng
Original file line number Diff line number Diff line change
Expand Up @@ -959,6 +959,13 @@
<param name="pattern">.*\S.*</param>
</data>
</element>
<element name="Attribute">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry I missed this. It looks like you forgot to update the schema and XML printing.

<attribute name="attributes"/>
<!-- Non-empty text content. -->
<data type="string">
<param name="pattern">.*\S.*</param>
</data>
</element>
</choice>
</define>

Expand Down
26 changes: 26 additions & 0 deletions include/swift/Markup/AST.h
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,32 @@ class Image final : public InlineContent,
}
};

class Attribute final : public InlineContent, private llvm::TrailingObjects<Image, MarkupASTNode *> {
friend TrailingObjects;

size_t NumChildren;
StringRef Attributes;

Attribute(StringRef Attributes, ArrayRef<MarkupASTNode *> Children);

public:
static Attribute *create(MarkupContext &MC, StringRef Attributes, ArrayRef<MarkupASTNode *> Children);

StringRef getAttributes() const { return Attributes; }

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::Attribute;
}
};

#pragma mark Private Extensions

class PrivateExtension : public MarkupASTNode {
Expand Down
3 changes: 2 additions & 1 deletion include/swift/Markup/ASTNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ ABSTRACT_MARKUP_AST_NODE(InlineContent, MarkupASTNode)
MARKUP_AST_NODE(Strong, InlineContent)
MARKUP_AST_NODE(Link, InlineContent)
MARKUP_AST_NODE(Image, InlineContent)
MARKUP_AST_NODE_RANGE(Inline, Text, Image)
MARKUP_AST_NODE(Attribute, InlineContent)
MARKUP_AST_NODE_RANGE(Inline, Text, Attribute)

/// Private Markdown Extensions - these should not be implemented in the
/// underlying cmark parser.
Expand Down
9 changes: 9 additions & 0 deletions lib/Frontend/PrintingDiagnosticConsumer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,15 @@ namespace {
}
}

void visitAttribute(const Attribute *A) {
print("^[");
for (const auto *Child : A->getChildren())
visit(Child);
print("](");
print(A->getAttributes());
print(")");
}

void visitBlockQuote(const BlockQuote *BQ) {
indent();
printNewline();
Expand Down
18 changes: 18 additions & 0 deletions lib/IDE/CommentConversion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,18 @@ struct CommentToXMLConverter {
llvm_unreachable("Can't print a swift::markup::Document as XML directly");
}

void printAttribute(const Attribute *A) {
OS << "<Attribute attributes=\"";
appendWithXMLEscaping(OS, A->getAttributes());
OS << "\">";

for (const auto *N : A->getChildren()) {
printASTNode(N);
}

OS << "</Attribute>";
}

void printBlockQuote(const BlockQuote *BQ) {
for (const auto *N : BQ->getChildren())
printASTNode(N);
Expand Down Expand Up @@ -638,6 +650,12 @@ class DoxygenConverter : public MarkupASTVisitor<DoxygenConverter> {
visit(Child);
}

void visitAttribute(const Attribute *A) {
// attributed strings don't have an analogue in Doxygen, so just print out the text
for (const auto *Child : A->getChildren())
visit(Child);
}

void visitBlockQuote(const BlockQuote *BQ) {
print("<blockquote>");
printNewline();
Expand Down
18 changes: 18 additions & 0 deletions lib/Markup/AST.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,16 @@ Paragraph *Paragraph::create(MarkupContext &MC,
return new (Mem) Paragraph(Children);
}

Attribute::Attribute(StringRef Attributes, ArrayRef<MarkupASTNode *> Children) : InlineContent(ASTNodeKind::Attribute), NumChildren(Children.size()), Attributes(Attributes) {
std::uninitialized_copy(Children.begin(), Children.end(), getTrailingObjects<MarkupASTNode *>());
}

Attribute *Attribute::create(MarkupContext &MC, StringRef Attributes, ArrayRef<MarkupASTNode *> Children) {
void *Mem = MC.allocate(totalSizeToAlloc<MarkupASTNode *>(Children.size()), alignof(Attribute));
StringRef AttrsCopy = MC.allocateCopy(Attributes);
return new (Mem) Attribute(AttrsCopy, Children);
}

HRule *HRule::create(MarkupContext &MC) {
void *Mem = MC.allocate(sizeof(HRule), alignof(HRule));
return new (Mem) HRule();
Expand Down Expand Up @@ -408,6 +418,14 @@ void swift::markup::dump(const MarkupASTNode *Node, llvm::raw_ostream &OS,
dumpChildren(Node->getChildren(), OS, indent + 1);
break;
}
case swift::markup::ASTNodeKind::Attribute: {
auto A = cast<Attribute>(Node);
OS << "Attribute:";
OS << " Attributes=" << A->getAttributes();
OS << " Children=" << Node->getChildren().size();
dumpChildren(Node->getChildren(), OS, indent + 1);
break;
}
case swift::markup::ASTNodeKind::BlockQuote: {
OS << "BlockQuote: Children=" << Node->getChildren().size();
dumpChildren(Node->getChildren(), OS, indent + 1);
Expand Down
40 changes: 28 additions & 12 deletions lib/Markup/Markup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ ParseResult<Strong> parseStrong(MarkupContext &MC, ParseState State) {
}

ParseResult<Header> parseHeader(MarkupContext &MC, ParseState State) {
assert(cmark_node_get_type(State.Node) == CMARK_NODE_HEADER
assert(cmark_node_get_type(State.Node) == CMARK_NODE_HEADING
&& State.Event == CMARK_EVENT_ENTER);
auto Level = cmark_node_get_header_level(State.Node);
SmallVector<MarkupASTNode *, 2> Children;
Expand All @@ -149,19 +149,19 @@ ParseResult<Header> parseHeader(MarkupContext &MC, ParseState State) {
}

ParseResult<HRule> parseHRule(MarkupContext &MC, ParseState State) {
assert(cmark_node_get_type(State.Node) == CMARK_NODE_HRULE
assert(cmark_node_get_type(State.Node) == CMARK_NODE_THEMATIC_BREAK
&& State.Event == CMARK_EVENT_ENTER);
return { HRule::create(MC), State.next() };
}

ParseResult<HTML> parseHTML(MarkupContext &MC, ParseState State) {
assert(cmark_node_get_type(State.Node) == CMARK_NODE_HTML
assert(cmark_node_get_type(State.Node) == CMARK_NODE_HTML_BLOCK
&& State.Event == CMARK_EVENT_ENTER);
return {HTML::create(MC, getLiteralContent(MC, State.Node)), State.next()};
}

ParseResult<InlineHTML> parseInlineHTML(MarkupContext &MC, ParseState State) {
assert(cmark_node_get_type(State.Node) == CMARK_NODE_INLINE_HTML
assert(cmark_node_get_type(State.Node) == CMARK_NODE_HTML_INLINE
&& State.Event == CMARK_EVENT_ENTER);
return {InlineHTML::create(MC, getLiteralContent(MC, State.Node)),
State.next()};
Expand Down Expand Up @@ -216,6 +216,15 @@ ParseResult<Link> parseLink(MarkupContext &MC, ParseState State) {
return { Link::create(MC, Destination, Children), ResultState.next() };
}

ParseResult<Attribute> parseAttribute(MarkupContext &MC, ParseState State) {
assert(cmark_node_get_type(State.Node) == CMARK_NODE_ATTRIBUTE && State.Event == CMARK_EVENT_ENTER);
std::string Attributes(cmark_node_get_attributes(State.Node));
SmallVector<MarkupASTNode *, 2> Children;
auto ResultState = parseChildren(MC, State, Children);
assert(State.Node == ResultState.Node && ResultState.Event == CMARK_EVENT_EXIT);
return { Attribute::create(MC, Attributes, Children), ResultState.next() };
}

ParseResult<List> parseList(MarkupContext &MC, ParseState State) {
assert(cmark_node_get_type(State.Node) == CMARK_NODE_LIST
&& State.Event == CMARK_EVENT_ENTER);
Expand Down Expand Up @@ -245,6 +254,13 @@ ParseResult<MarkupASTNode> parseElement(MarkupContext &MC, ParseState State) {
case CMARK_NODE_DOCUMENT: {
llvm_unreachable("Markup documents cannot be nested");
}
case CMARK_NODE_FOOTNOTE_REFERENCE:
case CMARK_NODE_FOOTNOTE_DEFINITION: {
llvm_unreachable("Footnotes are not currently parsed by swiftMarkup");
}
case CMARK_NODE_ATTRIBUTE: {
return parseAttribute(MC, State);
}
case CMARK_NODE_BLOCK_QUOTE: {
return parseBlockQuote(MC, State);
}
Expand All @@ -257,21 +273,18 @@ ParseResult<MarkupASTNode> parseElement(MarkupContext &MC, ParseState State) {
case CMARK_NODE_EMPH: {
return parseEmphasis(MC, State);
}
case CMARK_NODE_HEADER: {
case CMARK_NODE_HEADING: {
return parseHeader(MC, State);
}
case CMARK_NODE_HRULE: {
return parseHRule(MC, State);
}
case CMARK_NODE_HTML: {
case CMARK_NODE_HTML_BLOCK: {
return parseHTML(MC, State);
}
case CMARK_NODE_HTML_INLINE: {
return parseInlineHTML(MC, State);
}
case CMARK_NODE_IMAGE: {
return parseImage(MC, State);
}
case CMARK_NODE_INLINE_HTML: {
return parseInlineHTML(MC, State);
}
case CMARK_NODE_ITEM: {
return parseItem(MC, State);
}
Expand All @@ -296,6 +309,9 @@ ParseResult<MarkupASTNode> parseElement(MarkupContext &MC, ParseState State) {
case CMARK_NODE_TEXT: {
return parseText(MC, State);
}
case CMARK_NODE_THEMATIC_BREAK: {
return parseHRule(MC, State);
}
default: {
llvm_unreachable("Can't parse a Markup node of type 'None'");
}
Expand Down
21 changes: 21 additions & 0 deletions test/Inputs/comment_to_something_conversion.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,15 @@ public enum A012_AttachToEntities {
// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f0()</Name><USR>c:@M@comment_to_xml@objc(cs)ATXHeaders(im)f0</USR><Declaration>@objc public func f0()</Declaration><CommentParts><Discussion><rawHTML><![CDATA[<h1>]]></rawHTML>LEVEL ONE<rawHTML><![CDATA[</h1>]]></rawHTML><rawHTML><![CDATA[<h2>]]></rawHTML>LEVEL TWO<rawHTML><![CDATA[</h2>]]></rawHTML></Discussion></CommentParts></Function>]
}

@objc public class Attributes {
// CHECK: {{.*}}DocCommentAsXML=none
/// Here is an attribute:
///
/// ^[Attribute text](string: "attributed")
@objc public func f0() {}
// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f0()</Name><USR>c:@M@comment_to_xml@objc(cs)Attributes(im)f0</USR><Declaration>@objc public func f0()</Declaration><CommentParts><Abstract><Para>Here is an attribute:</Para></Abstract><Discussion><Para><Attribute attributes="string: &quot;attributed&quot;">Attribute text</Attribute></Para></Discussion></CommentParts></Function>]
}

@objc public class AutomaticLink {
// CHECK: {{.*}}DocCommentAsXML=none
/// And now for a URL.
Expand Down Expand Up @@ -198,6 +207,18 @@ public enum A012_AttachToEntities {
// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f4()</Name><USR>c:@M@comment_to_xml@objc(cs)EmptyComments(im)f4</USR><Declaration>@objc public func f4()</Declaration><CommentParts><Abstract><Para>Aaa.</Para></Abstract></CommentParts></Function>]
}

@objc public class Footnotes {
// CHECK: {{.*}}DocCommentAsXML=none
/// Has some footnotes.
///
/// Footnotes aren't handled by swiftMarkup yet[^footnote], but they may in the future.
///
/// [^footnote]: Footnotes aren't parsed by default in swift-cmark, and swiftMarkup doesn't
/// enable the feature.
@objc public func f0() {}
// CHECK: {{.*}}DocCommentAsXML=[<Function file="{{.*}}" line="{{.*}}" column="{{.*}}"><Name>f0()</Name><USR>c:@M@comment_to_xml@objc(cs)Footnotes(im)f0</USR><Declaration>@objc public func f0()</Declaration><CommentParts><Abstract><Para>Has some footnotes.</Para></Abstract><Discussion><Para>Footnotes aren’t handled by swiftMarkup yet[^footnote], but they may in the future.</Para><Para>[^footnote]: Footnotes aren’t parsed by default in swift-cmark, and swiftMarkup doesn’t enable the feature.</Para></Discussion></CommentParts></Function>]
}

@objc public class HasThrowingFunction {
// CHECK: {{.*}}DocCommentAsXML=none

Expand Down
18 changes: 18 additions & 0 deletions test/PrintAsObjC/Inputs/comments-expected-output.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ SWIFT_CLASS("_TtC8comments10ATXHeaders")
@end


SWIFT_CLASS("_TtC8comments10Attributes")
@interface Attributes
/// Here is an attribute:
/// Attribute text
- (void)f0;
@end


SWIFT_CLASS("_TtC8comments13AutomaticLink")
@interface AutomaticLink
/// And now for a URL.
Expand Down Expand Up @@ -185,6 +193,16 @@ SWIFT_CLASS("_TtC8comments13EmptyComments")
@end


SWIFT_CLASS("_TtC8comments9Footnotes")
@interface Footnotes
/// Has some footnotes.
/// Footnotes aren’t handled by swiftMarkup yet[^footnote], but they may in the future.
/// [^footnote]: Footnotes aren’t parsed by default in swift-cmark, and swiftMarkup doesn’t
/// enable the feature.
- (void)f0;
@end


SWIFT_CLASS("_TtC8comments19HasThrowingFunction")
@interface HasThrowingFunction
/// Might throw something.
Expand Down