--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/DocCommentParser.java Thu Nov 30 07:54:28 2017 -0500
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/DocCommentParser.java Thu Nov 30 04:43:09 2017 -0800
@@ -36,10 +36,12 @@
import com.sun.tools.javac.tree.DCTree;
import com.sun.tools.javac.tree.DCTree.DCAttribute;
import com.sun.tools.javac.tree.DCTree.DCDocComment;
+import com.sun.tools.javac.tree.DCTree.DCEndElement;
import com.sun.tools.javac.tree.DCTree.DCEndPosTree;
import com.sun.tools.javac.tree.DCTree.DCErroneous;
import com.sun.tools.javac.tree.DCTree.DCIdentifier;
import com.sun.tools.javac.tree.DCTree.DCReference;
+import com.sun.tools.javac.tree.DCTree.DCStartElement;
import com.sun.tools.javac.tree.DCTree.DCText;
import com.sun.tools.javac.tree.DocTreeMaker;
import com.sun.tools.javac.tree.JCTree;
@@ -50,6 +52,7 @@
import com.sun.tools.javac.util.Name;
import com.sun.tools.javac.util.Names;
import com.sun.tools.javac.util.Position;
+import com.sun.tools.javac.util.StringUtils;
import static com.sun.tools.javac.util.LayoutCharacters.*;
@@ -68,11 +71,14 @@
}
}
+ private enum Phase {PREAMBLE, BODY, POSTAMBLE};
+
final ParserFactory fac;
final DiagnosticSource diagSource;
final Comment comment;
final DocTreeMaker m;
final Names names;
+ final boolean isFileContent;
BreakIterator sentenceBreaker;
@@ -93,17 +99,23 @@
Map<Name, TagParser> tagParsers;
- public DocCommentParser(ParserFactory fac, DiagnosticSource diagSource, Comment comment) {
+ public DocCommentParser(ParserFactory fac, DiagnosticSource diagSource,
+ Comment comment, boolean isFileContent) {
this.fac = fac;
this.diagSource = diagSource;
this.comment = comment;
names = fac.names;
+ this.isFileContent = isFileContent;
m = fac.docTreeMaker;
initTagParsers();
}
+ public DocCommentParser(ParserFactory fac, DiagnosticSource diagSource, Comment comment) {
+ this(fac, diagSource, comment, false);
+ }
+
public DocCommentParser(ParserFactory fac) {
- this(fac, null, null);
+ this(fac, null, null, false);
}
public DCDocComment parse() {
@@ -115,13 +127,22 @@
bp = -1;
nextChar();
- List<DCTree> body = blockContent();
+ List<DCTree> preamble = isFileContent ? blockContent(Phase.PREAMBLE) : List.nil();
+ List<DCTree> body = blockContent(Phase.BODY);
List<DCTree> tags = blockTags();
- int pos = !body.isEmpty()
- ? body.head.pos
- : !tags.isEmpty() ? tags.head.pos : Position.NOPOS;
+ List<DCTree> postamble = isFileContent ? blockContent(Phase.POSTAMBLE) : List.nil();
- DCDocComment dc = m.at(pos).newDocCommentTree(comment, body, tags);
+ int pos = Position.NOPOS;
+ if (!preamble.isEmpty())
+ pos = preamble.head.pos;
+ else if (!body.isEmpty())
+ pos = body.head.pos;
+ else if (!tags.isEmpty())
+ pos = tags.head.pos;
+ else if (!postamble.isEmpty())
+ pos = postamble.head.pos;
+
+ DCDocComment dc = m.at(pos).newDocCommentTree(comment, body, tags, preamble, postamble);
return dc;
}
@@ -133,13 +154,17 @@
}
}
+ protected List<DCTree> blockContent() {
+ return blockContent(Phase.BODY);
+ }
+
/**
* Read block content, consisting of text, html and inline tags.
* Terminated by the end of input, or the beginning of the next block tag:
* i.e. @ as the first non-whitespace character on a line.
*/
@SuppressWarnings("fallthrough")
- protected List<DCTree> blockContent() {
+ protected List<DCTree> blockContent(Phase phase) {
ListBuffer<DCTree> trees = new ListBuffer<>();
textStart = -1;
@@ -160,8 +185,36 @@
case '<':
newline = false;
+ if (isFileContent) {
+ switch (phase) {
+ case PREAMBLE:
+ if (peek("body")) {
+ trees.add(html());
+ if (textStart == -1) {
+ textStart = bp;
+ lastNonWhite = -1;
+ }
+ // mark this as the start, for processing purposes
+ newline = true;
+ break loop;
+ }
+ break;
+ case BODY:
+ if (peek("/body")) {
+ addPendingText(trees, lastNonWhite);
+ break loop;
+ }
+ break;
+ default:
+ // fallthrough
+ }
+ }
addPendingText(trees, bp - 1);
trees.add(html());
+
+ if (phase == Phase.PREAMBLE || phase == Phase.POSTAMBLE) {
+ break; // Ignore newlines after html tags, in the meta content
+ }
if (textStart == -1) {
textStart = bp;
lastNonWhite = -1;
@@ -734,11 +787,37 @@
}
}
+ boolean peek(String s) {
+ final int savedpos = bp;
+ try {
+ if (ch == '<')
+ nextChar();
+
+ if (ch == '/') {
+ if (s.charAt(0) != ch) {
+ return false;
+ } else {
+ s = s.substring(1, s.length());
+ nextChar();
+ }
+ }
+
+ if (isIdentifierStart(ch)) {
+ Name name = readIdentifier();
+ return StringUtils.toLowerCase(name.toString()).equals(s);
+ }
+ return false;
+ } finally {
+ bp = savedpos;
+ ch = buf[bp];
+ }
+ }
+
/**
* Read the start or end of an HTML tag, or an HTML comment
* {@literal <identifier attrs> } or {@literal </identifier> }
*/
- protected DCTree html() {
+ private DCTree html() {
int p = bp;
nextChar();
if (isIdentifierStart(ch)) {
@@ -790,6 +869,19 @@
nextChar();
}
}
+ } else if (isIdentifierStart(ch) && peek("doctype")) {
+ readIdentifier();
+ nextChar();
+ skipWhitespace();
+ int d = bp;
+ while (bp < buflen) {
+ if (ch == '>') {
+ int mark = bp;
+ nextChar();
+ return m.at(d).newDocTypeTree(newString(d, mark));
+ }
+ nextChar();
+ }
}
}
@@ -1316,4 +1408,5 @@
tagParsers.put(names.fromString(p.getTreeKind().tagName), p);
}
+
}