Java源码示例:org.commonmark.internal.util.Parsing
示例1
/**
* The main parsing function. Returns a parsed document AST.
*/
public Document parse(String input) {
int lineStart = 0;
int lineBreak;
while ((lineBreak = Parsing.findLineBreak(input, lineStart)) != -1) {
CharSequence line = Substring.of(input, lineStart, lineBreak);
incorporateLine(line);
if (lineBreak + 1 < input.length() && input.charAt(lineBreak) == '\r' && input.charAt(lineBreak + 1) == '\n') {
lineStart = lineBreak + 2;
} else {
lineStart = lineBreak + 1;
}
}
if (input.length() > 0 && (lineStart == 0 || lineStart < input.length())) {
incorporateLine(Substring.of(input, lineStart, input.length()));
}
return finalizeAndProcess();
}
示例2
/**
* Add line content to the active block parser. We assume it can accept lines -- that check should be done before
* calling this.
*/
private void addLine() {
CharSequence content;
if (columnIsInTab) {
// Our column is in a partially consumed tab. Expand the remaining columns (to the next tab stop) to spaces.
int afterTab = index + 1;
CharSequence rest = line.subSequence(afterTab, line.length());
int spaces = Parsing.columnsToNextTabStop(column);
StringBuilder sb = new StringBuilder(spaces + rest.length());
for (int i = 0; i < spaces; i++) {
sb.append(' ');
}
sb.append(rest);
content = sb.toString();
} else {
content = line.subSequence(index, line.length());
}
getActiveBlockParser().addLine(content);
}
示例3
public void closeBlock(ReferenceParser inlineParser) {
String contentString = content.getString();
boolean hasReferenceDefs = false;
int pos;
// try parsing the beginning as link reference definitions:
while (contentString.length() > 3 && contentString.charAt(0) == '[' &&
(pos = inlineParser.parseReference(contentString)) != 0) {
contentString = contentString.substring(pos);
hasReferenceDefs = true;
}
if (hasReferenceDefs && Parsing.isBlank(contentString)) {
block.unlink();
content = null;
} else {
content = new BlockContent(contentString);
}
}
示例4
@Override
public BlockContinue tryContinue(ParserState parserState) {
final int nextNonSpaceIndex = parserState.getNextNonSpaceIndex();
final CharSequence line = parserState.getLine();
final int length = line.length();
// check for closing
if (parserState.getIndent() < Parsing.CODE_BLOCK_INDENT) {
if (consume(DOLLAR, line, nextNonSpaceIndex, length) == signs) {
// okay, we have our number of signs
// let's consume spaces until the end
if (Parsing.skip(SPACE, line, nextNonSpaceIndex + signs, length) == length) {
return BlockContinue.finished();
}
}
}
return BlockContinue.atIndex(parserState.getIndex());
}
示例5
@Override
public BlockStart tryStart(ParserState state, MatchedBlockParser matchedBlockParser) {
final int nextNonSpace = state.getNextNonSpaceIndex();
return isStartedMarker(state, nextNonSpace)
.map( m -> {
int newColumn = state.getColumn() + state.getIndent() + 1;
// optional following space or tab
if (Parsing.isSpaceOrTab(state.getLine(), nextNonSpace + 1)) {
newColumn++;
}
final NoticeBlock block = new NoticeBlock( NoticeBlock.Type.fromString(m.group(1)), m.group(2)) ;
final NoticeBlockParser parser = new NoticeBlockParser( block );
return BlockStart.of(parser).atColumn(newColumn +m.end());
})
.orElseGet( () -> BlockStart.none() );
}
示例6
@Override
public void closeBlock() {
int lastNonBlank = lines.size() - 1;
while (lastNonBlank >= 0) {
if (!Parsing.isBlank(lines.get(lastNonBlank))) {
break;
}
lastNonBlank--;
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < lastNonBlank + 1; i++) {
sb.append(lines.get(i));
sb.append('\n');
}
String literal = sb.toString();
block.setLiteral(literal);
}
示例7
@Override
public BlockStart tryStart(ParserState state, MatchedBlockParser matchedBlockParser) {
if (state.getIndent() >= Parsing.CODE_BLOCK_INDENT) {
return BlockStart.none();
}
CharSequence line = state.getLine();
int nextNonSpace = state.getNextNonSpaceIndex();
HeadingParser atxHeading = getAtxHeading(line, nextNonSpace);
if (atxHeading != null) {
return BlockStart.of(atxHeading).atIndex(line.length());
}
int setextHeadingLevel = getSetextHeadingLevel(line, nextNonSpace);
if (setextHeadingLevel > 0) {
CharSequence paragraph = matchedBlockParser.getParagraphContent();
if (paragraph != null) {
String content = paragraph.toString();
return BlockStart.of(new HeadingParser(setextHeadingLevel, content))
.atIndex(line.length())
.replaceActiveBlockParser();
}
}
return BlockStart.none();
}
示例8
@Override
public BlockContinue tryContinue(ParserState state) {
int nextNonSpace = state.getNextNonSpaceIndex();
int newIndex = state.getIndex();
CharSequence line = state.getLine();
boolean closing = state.getIndent() < Parsing.CODE_BLOCK_INDENT && isClosing(line, nextNonSpace);
if (closing) {
// closing fence - we're at end of line, so we can finalize now
return BlockContinue.finished();
} else {
// skip optional spaces of fence indent
int i = block.getFenceIndent();
int length = line.length();
while (i > 0 && newIndex < length && line.charAt(newIndex) == ' ') {
newIndex++;
i--;
}
}
return BlockContinue.atIndex(newIndex);
}
示例9
/**
* Add line content to the active block parser. We assume it can accept lines -- that check should be done before
* calling this.
*/
private void addLine() {
CharSequence content;
if (columnIsInTab) {
// Our column is in a partially consumed tab. Expand the remaining columns (to the next tab stop) to spaces.
int afterTab = index + 1;
CharSequence rest = line.subSequence(afterTab, line.length());
int spaces = Parsing.columnsToNextTabStop(column);
StringBuilder sb = new StringBuilder(spaces + rest.length());
for (int i = 0; i < spaces; i++) {
sb.append(' ');
}
sb.append(rest);
content = sb.toString();
} else {
content = line.subSequence(index, line.length());
}
getActiveBlockParser().addLine(content);
}
示例10
private int startDefinition(CharSequence line, int i) {
i = Parsing.skipSpaceTab(line, i, line.length());
if (i >= line.length() || line.charAt(i) != '[') {
return -1;
}
state = State.LABEL;
label = new StringBuilder();
int labelStart = i + 1;
if (labelStart >= line.length()) {
label.append('\n');
}
return labelStart;
}
示例11
private int destination(CharSequence line, int i) {
i = Parsing.skipSpaceTab(line, i, line.length());
int afterDestination = LinkScanner.scanLinkDestination(line, i);
if (afterDestination == -1) {
return -1;
}
destination = (line.charAt(i) == '<')
? line.subSequence(i + 1, afterDestination - 1).toString()
: line.subSequence(i, afterDestination).toString();
int afterSpace = Parsing.skipSpaceTab(line, afterDestination, line.length());
if (afterSpace >= line.length()) {
// Destination was at end of line, so this is a valid reference for sure (and maybe a title).
// If not at end of line, wait for title to be valid first.
referenceValid = true;
paragraph.setLength(0);
} else if (afterSpace == afterDestination) {
// spec: The title must be separated from the link destination by whitespace
return -1;
}
state = State.START_TITLE;
return afterSpace;
}
示例12
@Override
public BlockContinue tryContinue(ParserState state) {
if (state.getIndent() >= Parsing.CODE_BLOCK_INDENT) {
return BlockContinue.atColumn(state.getColumn() + Parsing.CODE_BLOCK_INDENT);
} else if (state.isBlank()) {
return BlockContinue.atIndex(state.getNextNonSpaceIndex());
} else {
return BlockContinue.none();
}
}
示例13
@Override
public BlockStart tryStart(ParserState state, MatchedBlockParser matchedBlockParser) {
// An indented code block cannot interrupt a paragraph.
if (state.getIndent() >= Parsing.CODE_BLOCK_INDENT && !state.isBlank() && !(state.getActiveBlockParser().getBlock() instanceof Paragraph)) {
return BlockStart.of(new IndentedCodeBlockParser()).atColumn(state.getColumn() + Parsing.CODE_BLOCK_INDENT);
} else {
return BlockStart.none();
}
}
示例14
@Override
public BlockStart tryStart(ParserState state, MatchedBlockParser matchedBlockParser) {
BlockParser matched = matchedBlockParser.getMatchedBlockParser();
if (state.getIndent() >= Parsing.CODE_BLOCK_INDENT && !(matched instanceof ListBlockParser)) {
return BlockStart.none();
}
int markerIndex = state.getNextNonSpaceIndex();
int markerColumn = state.getColumn() + state.getIndent();
boolean inParagraph = matchedBlockParser.getParagraphContent() != null;
ListData listData = parseListMarker(state.getLine(), markerIndex, markerColumn, inParagraph);
if (listData == null) {
return BlockStart.none();
}
int newColumn = listData.contentColumn;
ListItemParser listItemParser = new ListItemParser(newColumn - state.getColumn());
// prepend the list block if needed
if (!(matched instanceof ListBlockParser) ||
!(listsMatch((ListBlock) matched.getBlock(), listData.listBlock))) {
ListBlockParser listBlockParser = new ListBlockParser(listData.listBlock);
listBlockParser.setTight(true);
return BlockStart.of(listBlockParser, listItemParser).atColumn(newColumn);
} else {
return BlockStart.of(listItemParser).atColumn(newColumn);
}
}
示例15
private void advance() {
char c = line.charAt(index);
if (c == '\t') {
index++;
column += Parsing.columnsToNextTabStop(column);
} else {
index++;
column++;
}
}
示例16
@Override
public BlockContinue tryContinue(ParserState state) {
int nextNonSpace = state.getNextNonSpaceIndex();
if (isMarker(state, nextNonSpace)) {
int newColumn = state.getColumn() + state.getIndent() + 1;
// optional following space or tab
if (Parsing.isSpaceOrTab(state.getLine(), nextNonSpace + 1)) {
newColumn++;
}
return BlockContinue.atColumn(newColumn);
} else {
return BlockContinue.none();
}
}
示例17
public BlockStart tryStart(ParserState state, MatchedBlockParser matchedBlockParser) {
int nextNonSpace = state.getNextNonSpaceIndex();
if (isMarker(state, nextNonSpace)) {
int newColumn = state.getColumn() + state.getIndent() + 1;
// optional following space or tab
if (Parsing.isSpaceOrTab(state.getLine(), nextNonSpace + 1)) {
newColumn++;
}
return BlockStart.of(new BlockQuoteParser()).atColumn(newColumn);
} else {
return BlockStart.none();
}
}
示例18
@Override
protected Node parse() {
String ticks = match(TICKS_HERE);
if (ticks == null) {
return null;
}
int afterOpenTicks = index;
String matched;
while ((matched = match(TICKS)) != null) {
if (matched.equals(ticks)) {
Code node = new Code();
String content = input.substring(afterOpenTicks, index - ticks.length());
content = content.replace('\n', ' ');
// spec: If the resulting string both begins and ends with a space character, but does not consist
// entirely of space characters, a single space character is removed from the front and back.
if (content.length() >= 3 &&
content.charAt(0) == ' ' &&
content.charAt(content.length() - 1) == ' ' &&
Parsing.hasNonSpace(content)) {
content = content.substring(1, content.length() - 1);
}
node.setLiteral(content);
return node;
}
}
// If we got here, we didn't match a closing backtick sequence.
index = afterOpenTicks;
return text(ticks);
}
示例19
@Override
public BlockStart tryStart(ParserState state, MatchedBlockParser matchedBlockParser) {
// let's define the spec:
// * 0-3 spaces before are allowed (Parsing.CODE_BLOCK_INDENT = 4)
// * 2+ subsequent `$` signs
// * any optional amount of spaces
// * new line
// * block is closed when the same amount of opening signs is met
final int indent = state.getIndent();
// check if it's an indented code block
if (indent >= Parsing.CODE_BLOCK_INDENT) {
return BlockStart.none();
}
final int nextNonSpaceIndex = state.getNextNonSpaceIndex();
final CharSequence line = state.getLine();
final int length = line.length();
final int signs = consume(DOLLAR, line, nextNonSpaceIndex, length);
// 2 is minimum
if (signs < 2) {
return BlockStart.none();
}
// consume spaces until the end of the line, if any other content is found -> NONE
if (Parsing.skip(SPACE, line, nextNonSpaceIndex + signs, length) != length) {
return BlockStart.none();
}
return BlockStart.of(new JLatexMathBlockParser(signs))
.atIndex(length + 1);
}
示例20
@Test
public void factory_indentBlock() {
// when state indent is greater than block -> nono
final ParserState state = mock(ParserState.class);
when(state.getIndent()).thenReturn(Parsing.CODE_BLOCK_INDENT);
// hm, interesting, `BlockStart.none()` actually returns null
final BlockStart start = factory.tryStart(state, null);
assertNull(start);
}
示例21
@Override
public BlockContinue tryContinue(ParserState state) {
int nextNonSpace = state.getNextNonSpaceIndex();
if (isMarker(state, nextNonSpace)) {
int newColumn = state.getColumn() + state.getIndent() + 1;
// optional following space or tab
if (Parsing.isSpaceOrTab(state.getLine(), nextNonSpace + 1)) {
newColumn++;
}
return BlockContinue.atColumn(newColumn);
} else {
return BlockContinue.none();
}
}
示例22
private static Optional<Matcher> isStartedMarker(ParserState state, int index) {
final CharSequence line = state.getLine();
return ( state.getIndent() < Parsing.CODE_BLOCK_INDENT && index < line.length() ) ?
ofNullable(pattern.matcher(line)).filter( m -> m.matches() ) :
Optional.empty();
}
示例23
@Override
public BlockContinue tryContinue(ParserState state) {
if (state.getIndent() >= Parsing.CODE_BLOCK_INDENT) {
return BlockContinue.atColumn(state.getColumn() + Parsing.CODE_BLOCK_INDENT);
} else if (state.isBlank()) {
return BlockContinue.atIndex(state.getNextNonSpaceIndex());
} else {
return BlockContinue.none();
}
}
示例24
@Override
public BlockStart tryStart(ParserState state, MatchedBlockParser matchedBlockParser) {
// An indented code block cannot interrupt a paragraph.
if (state.getIndent() >= Parsing.CODE_BLOCK_INDENT && !state.isBlank() && !(state.getActiveBlockParser().getBlock() instanceof Paragraph)) {
return BlockStart.of(new IndentedCodeBlockParser()).atColumn(state.getColumn() + Parsing.CODE_BLOCK_INDENT);
} else {
return BlockStart.none();
}
}
示例25
/**
* Attempt to parse backticks, returning either a backtick code span or a literal sequence of backticks.
*/
private Node parseBackticks() {
String ticks = match(TICKS_HERE);
if (ticks == null) {
return null;
}
int afterOpenTicks = index;
String matched;
while ((matched = match(TICKS)) != null) {
if (matched.equals(ticks)) {
Code node = new Code();
String content = input.substring(afterOpenTicks, index - ticks.length());
content = content.replace('\n', ' ');
// spec: If the resulting string both begins and ends with a space character, but does not consist
// entirely of space characters, a single space character is removed from the front and back.
if (content.length() >= 3 &&
content.charAt(0) == ' ' &&
content.charAt(content.length() - 1) == ' ' &&
Parsing.hasNonSpace(content)) {
content = content.substring(1, content.length() - 1);
}
node.setLiteral(content);
return node;
}
}
// If we got here, we didn't match a closing backtick sequence.
index = afterOpenTicks;
return text(ticks);
}
示例26
private static HeadingParser getAtxHeading(CharSequence line, int index) {
int level = Parsing.skip('#', line, index, line.length()) - index;
if (level == 0 || level > 6) {
return null;
}
int start = index + level;
if (start >= line.length()) {
// End of line after markers is an empty heading
return new HeadingParser(level, "");
}
char next = line.charAt(start);
if (!(next == ' ' || next == '\t')) {
return null;
}
int beforeSpace = Parsing.skipSpaceTabBackwards(line, line.length() - 1, start);
int beforeHash = Parsing.skipBackwards('#', line, beforeSpace, start);
int beforeTrailer = Parsing.skipSpaceTabBackwards(line, beforeHash, start);
if (beforeTrailer != beforeHash) {
return new HeadingParser(level, line.subSequence(start, beforeTrailer + 1).toString());
} else {
return new HeadingParser(level, line.subSequence(start, beforeSpace + 1).toString());
}
}
示例27
@Override
public BlockStart tryStart(ParserState state, MatchedBlockParser matchedBlockParser) {
int indent = state.getIndent();
if (indent >= Parsing.CODE_BLOCK_INDENT) {
return BlockStart.none();
}
int nextNonSpace = state.getNextNonSpaceIndex();
FencedCodeBlockParser blockParser = checkOpener(state.getLine(), nextNonSpace, indent);
if (blockParser != null) {
return BlockStart.of(blockParser).atIndex(nextNonSpace + blockParser.block.getFenceLength());
} else {
return BlockStart.none();
}
}
示例28
private static FencedCodeBlockParser checkOpener(CharSequence line, int index, int indent) {
int backticks = 0;
int tildes = 0;
int length = line.length();
loop:
for (int i = index; i < length; i++) {
switch (line.charAt(i)) {
case '`':
backticks++;
break;
case '~':
tildes++;
break;
default:
break loop;
}
}
if (backticks >= 3 && tildes == 0) {
// spec: If the info string comes after a backtick fence, it may not contain any backtick characters.
if (Parsing.find('`', line, index + backticks) != -1) {
return null;
}
return new FencedCodeBlockParser('`', backticks, indent);
} else if (tildes >= 3 && backticks == 0) {
// spec: Info strings for tilde code blocks can contain backticks and tildes
return new FencedCodeBlockParser('~', tildes, indent);
} else {
return null;
}
}
示例29
private boolean isClosing(CharSequence line, int index) {
char fenceChar = block.getFenceChar();
int fenceLength = block.getFenceLength();
int fences = Parsing.skip(fenceChar, line, index, line.length()) - index;
if (fences < fenceLength) {
return false;
}
// spec: The closing code fence [...] may be followed only by spaces, which are ignored.
int after = Parsing.skipSpaceTab(line, index + fences, line.length());
return after == line.length();
}
示例30
@Override
public BlockStart tryStart(ParserState state, MatchedBlockParser matchedBlockParser) {
BlockParser matched = matchedBlockParser.getMatchedBlockParser();
if (state.getIndent() >= Parsing.CODE_BLOCK_INDENT) {
return BlockStart.none();
}
int markerIndex = state.getNextNonSpaceIndex();
int markerColumn = state.getColumn() + state.getIndent();
boolean inParagraph = matchedBlockParser.getParagraphContent() != null;
ListData listData = parseList(state.getLine(), markerIndex, markerColumn, inParagraph);
if (listData == null) {
return BlockStart.none();
}
int newColumn = listData.contentColumn;
ListItemParser listItemParser = new ListItemParser(newColumn - state.getColumn());
// prepend the list block if needed
if (!(matched instanceof ListBlockParser) ||
!(listsMatch((ListBlock) matched.getBlock(), listData.listBlock))) {
ListBlockParser listBlockParser = new ListBlockParser(listData.listBlock);
// We start out with assuming a list is tight. If we find a blank line, we set it to loose later.
listData.listBlock.setTight(true);
return BlockStart.of(listBlockParser, listItemParser).atColumn(newColumn);
} else {
return BlockStart.of(listItemParser).atColumn(newColumn);
}
}