Node parseListBlock(StringBuilderVar block) { Context<Object> context = getContext(); Node innerRoot = parseInternal(block); setContext(context); // we need to save and restore the context since we might be recursing block.clearContents(); //debugMsg("parsed list block " + innerRoot.toString() + " adjusting indices by " + getContext().getValueStack().peek(), block.getString()); return withIndicesShifted(innerRoot, (Integer) context.getValueStack().pop()); }
public Rule Verbatim() { StringBuilderVar text = new StringBuilderVar(); StringBuilderVar line = new StringBuilderVar(); return NodeSequence( OneOrMore( ZeroOrMore(BlankLine(), line.append('\n')), Indent(), push(currentIndex()), OneOrMore( FirstOf( Sequence('\t', line.append(repeat(' ', 4-(currentIndex()-1-(Integer)peek())%4))), Sequence(NotNewline(), ANY, line.append(matchedChar())) ) ), Newline(), text.appended(line.getString()).append('\n') && line.clearContents() && drop() ), push(new VerbatimNode(text.getString())) ); }
public Rule ListItemIndentedBlocks(StringBuilderVar block) { StringBuilderVar line = new StringBuilderVar(); return Sequence( OneOrMore( Sequence( // vsch: Important! when accumulating text for recursive parsing it is critical that no characters, of the original text, are left out // if you don't want them to be parsed replace them with crossed out marker, they will be stripped before parsing but the index to the // source position will be correct. If you leave any characters out then the final index of the node will be offset by that many characters, // giving an incorrect result for the AST node. Yes it is critical if you use the AST for syntax highlighting of the source. ZeroOrMore(Sequence(CrossedOutLessOne(BlankLine(), line), line.append('\n'))), CrossedOut(Indent(), line), Line(line), // take the rest of the block's lines, with or without indentations, // but only if they are not a list item ZeroOrMore( TestNot(BlankLine()), TestNotListItem(), Optional(CrossedOut(Indent(), line)), Line(line) ), block.append(line.getString()) && line.clearContents() ) ), // if there is a blank line then we append \n, but leave the blank line for the next item, just in case it needs it // to determine looseness, however this can only be done for the last block in the indented set, otherwise // if we do it for each block then code blocks will have their embedded blank lines doubled and index positions will be off. Optional(Test(BlankLine(), line.append('\n'))) ); }
public Rule BlockQuote() { StringBuilderVar inner = new StringBuilderVar(); StringBuilderVar optional = new StringBuilderVar(); return NodeSequence( OneOrMore( CrossedOut(Sequence('>', Optional(' ')), inner), Line(inner), ZeroOrMore( TestNot('>'), TestNot(BlankLine()), Line(inner) ), // ZeroOrMore(BlankLine()), inner.append(match()) Optional(Sequence(OneOrMore(BlankLine()), optional.append(match()), Test('>')), inner.append(optional.getString()) && optional.clearContents()) ), // vsch: the block quotes won't parse into Para because they will not be followed by a blank line, // unless the last line of the block quote is an empty block-quote line: ">". We append one here to // take care of that possibility, now that we don't include blank lines after a block quote we add one extra inner.append("\n\n"), // trigger a recursive parsing run on the inner source we just built // and attach the root of the inner parses AST push(new BlockQuoteNode(withIndicesShifted(parseInternal(inner), (Integer) peek()).getChildren())) ); }
TestNotItem(), Line(temp), block.append(temp.getString()) && temp.clearContents() ), tight.get() ? push(tightFirstItem.setAndGet(itemNodeCreator.create(parseListBlock(block), taskType.get(), taskListMarker.getString()))) && taskListMarker.clearContents() : fixFirstItem((SuperNode) peek(1)) && push(itemNodeCreator.create(parseListBlock(block.appended('\n')), taskType.get(), taskListMarker.getString())) && taskListMarker.clearContents(), ZeroOrMore(
TestNotItem(), Line(temp), block.append(temp.getString()) && temp.clearContents() ),