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);
    }
}