package org.zwobble.mammoth.styles.parsing; import org.parboiled.BaseParser; import org.parboiled.Rule; import org.parboiled.support.Var; import org.zwobble.mammoth.styles.HtmlPath; import org.zwobble.mammoth.styles.HtmlPathElement; import static org.zwobble.mammoth.util.MammothMaps.map; public class HtmlPathParser extends BaseParser { public Rule HtmlPath() { ListVar elements = new ListVar<>(); return Sequence(Optional(HtmlPathElements(elements)), EOI, push(new HtmlPath(elements.build()))); } Rule HtmlPathElements(ListVar elements) { Var element = new Var<>(); return Sequence( HtmlPathElement(element), elements.append(element), ZeroOrMore(Sequence(Whitespace(), Ch('>'), Whitespace(), HtmlPathElement(element), elements.append(element)))); } Rule HtmlPathElement(Var element) { ListVar tagNames = new ListVar<>(); ListVar classNames = new ListVar<>(); Var fresh = new Var<>(); return Sequence( TagNames(tagNames), ClassNames(classNames), Fresh(fresh), element.set(new HtmlPathElement( tagNames.build(), classNames.isEmpty() ? map() : map("class", String.join(" ", classNames.build())), !fresh.get()))); } Rule TagNames(ListVar tagNames) { return Sequence( Identifier(), tagNames.append(match()), ZeroOrMore(Sequence("|", Identifier(), tagNames.append(match())))); } Rule ClassNames(ListVar classNames) { Var className = new Var<>(); return ZeroOrMore(Sequence(ClassName(className), classNames.append(className))); } Rule ClassName(Var className) { return Sequence(".", Identifier(), className.set(match())); } Rule Fresh(Var fresh) { return Sequence(fresh.set(false), Optional(":fresh", fresh.set(true))); } Rule Identifier() { return Sequence( FirstOf(CharRange('a', 'z'), CharRange('A', 'Z')), ZeroOrMore(FirstOf(CharRange('a', 'z'), CharRange('A', 'Z'), CharRange('0', '9'), Ch('-'), Ch('_')))); } Rule Whitespace() { return ZeroOrMore(AnyOf(" \t")); } }