aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/org/zwobble/mammoth/styles/parsing/HtmlPathParser.java
blob: 18e11073f0fb21a304cc750a0a86e455fd9c03ac (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
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<HtmlPath> {
    public Rule HtmlPath() {
        ListVar<HtmlPathElement> elements = new ListVar<>();
        return Sequence(Optional(HtmlPathElements(elements)), EOI, push(new HtmlPath(elements.build())));
    }

    Rule HtmlPathElements(ListVar<HtmlPathElement> elements) {
        Var<HtmlPathElement> element = new Var<>();
        return Sequence(
            HtmlPathElement(element),
            elements.append(element),
            ZeroOrMore(Sequence(Whitespace(), Ch('>'), Whitespace(), HtmlPathElement(element), elements.append(element))));
    }

    Rule HtmlPathElement(Var<HtmlPathElement> element) {
        ListVar<String> tagNames = new ListVar<>();
        ListVar<String> classNames = new ListVar<>();
        Var<Boolean> 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<String> tagNames) {
        return Sequence(
            Identifier(),
            tagNames.append(match()),
            ZeroOrMore(Sequence("|", Identifier(), tagNames.append(match()))));
    }

    Rule ClassNames(ListVar<String> classNames) {
        Var<String> className = new Var<>();
        return ZeroOrMore(Sequence(ClassName(className), classNames.append(className)));
    }

    Rule ClassName(Var<String> className) {
        return Sequence(".", Identifier(), className.set(match()));
    }

    Rule Fresh(Var<Boolean> 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"));
    }
}