diff --git a/core/src/main/java/com/google/googlejavaformat/java/javadoc/JavadocLexer.java b/core/src/main/java/com/google/googlejavaformat/java/javadoc/JavadocLexer.java index 546d5df35..f081571d8 100644 --- a/core/src/main/java/com/google/googlejavaformat/java/javadoc/JavadocLexer.java +++ b/core/src/main/java/com/google/googlejavaformat/java/javadoc/JavadocLexer.java @@ -95,10 +95,10 @@ private static String stripJavadocBeginAndEnd(String input) { } private final CharStream input; - private final NestingCounter braceDepth = new NestingCounter(); - private final NestingCounter preDepth = new NestingCounter(); - private final NestingCounter codeDepth = new NestingCounter(); - private final NestingCounter tableDepth = new NestingCounter(); + private final NestingStack braceStack = new NestingStack(); + private final NestingStack preStack = new NestingStack(); + private final NestingStack codeStack = new NestingStack(); + private final NestingStack tableStack = new NestingStack(); private boolean outerInlineTagIsSnippet; private boolean somethingSinceNewline; @@ -162,56 +162,56 @@ private Type consumeToken() throws LexException { somethingSinceNewline = true; if (input.tryConsumeRegex(SNIPPET_TAG_OPEN_PATTERN)) { - if (braceDepth.value() == 0) { - braceDepth.increment(); + if (braceStack.isEmpty()) { + braceStack.push(); outerInlineTagIsSnippet = true; return SNIPPET_BEGIN; } - braceDepth.increment(); + braceStack.push(); return LITERAL; } else if (input.tryConsumeRegex(INLINE_TAG_OPEN_PATTERN)) { - braceDepth.increment(); + braceStack.push(); return LITERAL; } else if (input.tryConsume("{")) { - braceDepth.incrementIfPositive(); + braceStack.incrementIfPositive(); return LITERAL; } else if (input.tryConsume("}")) { - if (outerInlineTagIsSnippet && braceDepth.value() == 1) { - braceDepth.decrementIfPositive(); + if (outerInlineTagIsSnippet && braceStack.total() == 1) { + braceStack.popIfNotEmpty(); outerInlineTagIsSnippet = false; return SNIPPET_END; } - braceDepth.decrementIfPositive(); + braceStack.popIfNotEmpty(); return LITERAL; } // Inside an inline tag, don't do any HTML interpretation. - if (braceDepth.isPositive()) { + if (!braceStack.isEmpty()) { verify(input.tryConsumeRegex(LITERAL_PATTERN)); return LITERAL; } if (input.tryConsumeRegex(PRE_OPEN_PATTERN)) { - preDepth.increment(); + preStack.push(); return preserveExistingFormatting ? LITERAL : PRE_OPEN_TAG; } else if (input.tryConsumeRegex(PRE_CLOSE_PATTERN)) { - preDepth.decrementIfPositive(); + preStack.popIfNotEmpty(); return preserveExistingFormatting() ? LITERAL : PRE_CLOSE_TAG; } if (input.tryConsumeRegex(CODE_OPEN_PATTERN)) { - codeDepth.increment(); + codeStack.push(); return preserveExistingFormatting ? LITERAL : CODE_OPEN_TAG; } else if (input.tryConsumeRegex(CODE_CLOSE_PATTERN)) { - codeDepth.decrementIfPositive(); + codeStack.popIfNotEmpty(); return preserveExistingFormatting() ? LITERAL : CODE_CLOSE_TAG; } if (input.tryConsumeRegex(TABLE_OPEN_PATTERN)) { - tableDepth.increment(); + tableStack.push(); return preserveExistingFormatting ? LITERAL : TABLE_OPEN_TAG; } else if (input.tryConsumeRegex(TABLE_CLOSE_PATTERN)) { - tableDepth.decrementIfPositive(); + tableStack.popIfNotEmpty(); return preserveExistingFormatting() ? LITERAL : TABLE_CLOSE_TAG; } @@ -255,17 +255,17 @@ private Type consumeToken() throws LexException { } private boolean preserveExistingFormatting() { - return preDepth.isPositive() - || tableDepth.isPositive() - || codeDepth.isPositive() + return !preStack.isEmpty() + || !tableStack.isEmpty() + || !codeStack.isEmpty() || outerInlineTagIsSnippet; } private void checkMatchingTags() throws LexException { - if (braceDepth.isPositive() - || preDepth.isPositive() - || tableDepth.isPositive() - || codeDepth.isPositive()) { + if (!braceStack.isEmpty() + || !preStack.isEmpty() + || !tableStack.isEmpty() + || !codeStack.isEmpty()) { throw new LexException(); } } diff --git a/core/src/main/java/com/google/googlejavaformat/java/javadoc/JavadocWriter.java b/core/src/main/java/com/google/googlejavaformat/java/javadoc/JavadocWriter.java index 427fcf51d..7f70b76b6 100644 --- a/core/src/main/java/com/google/googlejavaformat/java/javadoc/JavadocWriter.java +++ b/core/src/main/java/com/google/googlejavaformat/java/javadoc/JavadocWriter.java @@ -49,9 +49,9 @@ final class JavadocWriter { private boolean continuingListItemOfInnermostList; private boolean continuingFooterTag; - private final NestingCounter continuingListItemCount = new NestingCounter(); - private final NestingCounter continuingListCount = new NestingCounter(); - private final NestingCounter postWriteModifiedContinuingListCount = new NestingCounter(); + private final NestingStack continuingListItemStack = new NestingStack(); + private final NestingStack continuingListStack = new NestingStack(); + private final NestingStack postWriteModifiedContinuingListStack = new NestingStack(); private int remainingOnLine; private boolean atStartOfLine; private RequestedWhitespace requestedWhitespace = NONE; @@ -102,13 +102,13 @@ void writeFooterJavadocTagStart(Token token) { * currently know which of those tags are open. */ continuingListItemOfInnermostList = false; - continuingListItemCount.reset(); - continuingListCount.reset(); + continuingListItemStack.reset(); + continuingListStack.reset(); /* * There's probably no need for this, since its only effect is to disable blank lines in some * cases -- and we're doing that already in the footer. */ - postWriteModifiedContinuingListCount.reset(); + postWriteModifiedContinuingListStack.reset(); if (!wroteAnythingSignificant) { // Javadoc consists solely of tags. This is frowned upon in general but OK for @Overrides. @@ -161,8 +161,8 @@ void writeListOpen(Token token) { writeToken(token); continuingListItemOfInnermostList = false; - continuingListCount.increment(); - postWriteModifiedContinuingListCount.increment(); + continuingListStack.push(2); + postWriteModifiedContinuingListStack.push(); requestNewline(); } @@ -170,10 +170,10 @@ void writeListOpen(Token token) { void writeListClose(Token token) { requestNewline(); - continuingListItemCount.decrementIfPositive(); - continuingListCount.decrementIfPositive(); + continuingListItemStack.popIfNotEmpty(); + continuingListStack.popIfNotEmpty(); writeToken(token); - postWriteModifiedContinuingListCount.decrementIfPositive(); + postWriteModifiedContinuingListStack.popIfNotEmpty(); requestBlankLine(); } @@ -183,11 +183,11 @@ void writeListItemOpen(Token token) { if (continuingListItemOfInnermostList) { continuingListItemOfInnermostList = false; - continuingListItemCount.decrementIfPositive(); + continuingListItemStack.popIfNotEmpty(); } writeToken(token); continuingListItemOfInnermostList = true; - continuingListItemCount.increment(); + continuingListItemStack.push(4); } void writeHeaderOpen(Token token) { @@ -325,7 +325,7 @@ private void writeToken(Token token) { } if (requestedWhitespace == BLANK_LINE - && (postWriteModifiedContinuingListCount.isPositive() || continuingFooterTag)) { + && (!postWriteModifiedContinuingListStack.isEmpty() || continuingFooterTag)) { /* * We don't write blank lines inside lists or footer tags, even in cases where we otherwise * would (e.g., before a

tag). Justification: We don't write blank lines _between_ list @@ -418,7 +418,7 @@ enum AutoIndent { } private int innerIndent() { - int innerIndent = continuingListItemCount.value() * 4 + continuingListCount.value() * 2; + int innerIndent = continuingListItemStack.total() + continuingListStack.total(); if (continuingFooterTag) { innerIndent += 4; } diff --git a/core/src/main/java/com/google/googlejavaformat/java/javadoc/NestingCounter.java b/core/src/main/java/com/google/googlejavaformat/java/javadoc/NestingCounter.java deleted file mode 100644 index 43e7125c9..000000000 --- a/core/src/main/java/com/google/googlejavaformat/java/javadoc/NestingCounter.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2016 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ - -package com.google.googlejavaformat.java.javadoc; - -/** Mutable integer for tracking the level of nesting. */ -final class NestingCounter { - private int value; - - int value() { - return value; - } - - void increment() { - value++; - } - - void incrementIfPositive() { - if (value > 0) { - value++; - } - } - - void decrementIfPositive() { - if (value > 0) { - value--; - } - } - - boolean isPositive() { - return value > 0; - } - - void reset() { - value = 0; - } -} diff --git a/core/src/main/java/com/google/googlejavaformat/java/javadoc/NestingStack.java b/core/src/main/java/com/google/googlejavaformat/java/javadoc/NestingStack.java new file mode 100644 index 000000000..c029428df --- /dev/null +++ b/core/src/main/java/com/google/googlejavaformat/java/javadoc/NestingStack.java @@ -0,0 +1,63 @@ +/* + * Copyright 2016 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ + +package com.google.googlejavaformat.java.javadoc; + +import java.util.ArrayDeque; +import java.util.Deque; + +/** + * Stack for tracking the level of nesting. In the simplest case, each entry is just the integer 1, + * and the stack is effectively a counter. In more complex cases, the entries may depend on context. + * For example, if the stack is keeping track of Javadoc lists, the entries represent indentation + * levels, and those depend on whether the list is an HTML list or a Markdown list. + */ +final class NestingStack { + private int total; + private final Deque stack = new ArrayDeque<>(); + + int total() { + return total; + } + + void push() { + push(1); + } + + void push(int value) { + stack.push(value); + total += value; + } + + void incrementIfPositive() { + if (total > 0) { + push(); + } + } + + void popIfNotEmpty() { + if (!isEmpty()) { + total -= stack.pop(); + } + } + + boolean isEmpty() { + return stack.isEmpty(); + } + + void reset() { + total = 0; + stack.clear(); + } +}