Rule ListItem(boolean tight) {
// for a simpler parser design we use a recursive parsing strategy for list items:
// we collect the markdown source for an item, run a complete parsing cycle on this inner source and attach
// the root of the inner parsing results AST to the outer AST tree
StringVar innerSource = new StringVar();
StringVar blanks = new StringVar("");
StringVar extraNLs = new StringVar("");
return Sequence(
FirstOf(Bullet(), Enumerator()),
ListBlock(),
innerSource.set(pop().getText()) &&
(tight || extraNLs.set("\n\n")), // append extra \n\n to loose list items
ZeroOrMore(
FirstOf(
// if we have blank lines append them to the inner source
OneOrMore(BlankLine(), blanks.append("\n")),
// if we do not have a blank line we append a boundary marker
blanks.set(tight ? "\u0001" : "\n\n\u0001")
),
OneOrMore(
Indent(), ListBlock(),
// append potentially captured blanks and the block text
innerSource.append(blanks.getAndSet(""), pop().getText())
),
extraNLs.set("\n\n") // if we have several lines always add two extra newlines
),
// finally, after having built the complete source we run an inner parse and attach its AST root
setListItemNode(tight, innerSource.get() + extraNLs.get())
);
}