summaryrefslogtreecommitdiffstats
path: root/Doc/tools/extensions/peg_highlight.py
blob: 42101be10ea9b6c80580b6eeac1aa497f7349432 (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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
from pygments.lexer import RegexLexer, bygroups, include
from pygments.token import Comment, Generic, Keyword, Name, Operator, Punctuation, Text

from sphinx.highlighting import lexers


class PEGLexer(RegexLexer):
    """Pygments Lexer for PEG grammar (.gram) files

    This lexer strips the following elements from the grammar:

        - Meta-tags
        - Variable assignments
        - Actions
        - Lookaheads
        - Rule types
        - Rule options
        - Rules named `invalid_*` or `incorrect_*`
    """

    name = "PEG"
    aliases = ["peg"]
    filenames = ["*.gram"]
    _name = r"([^\W\d]\w*)"
    _text_ws = r"(\s*)"

    tokens = {
        "ws": [(r"\n", Text), (r"\s+", Text), (r"#.*$", Comment.Singleline),],
        "lookaheads": [
            # Forced tokens
            (r"(&&)(?=\w+\s?)", bygroups(None)),
            (r"(&&)(?='.+'\s?)", bygroups(None)),
            (r'(&&)(?=".+"\s?)', bygroups(None)),
            (r"(&&)(?=\(.+\)\s?)", bygroups(None)),

            (r"(?<=\|\s)(&\w+\s?)", bygroups(None)),
            (r"(?<=\|\s)(&'.+'\s?)", bygroups(None)),
            (r'(?<=\|\s)(&".+"\s?)', bygroups(None)),
            (r"(?<=\|\s)(&\(.+\)\s?)", bygroups(None)),
        ],
        "metas": [
            (r"(@\w+ '''(.|\n)+?''')", bygroups(None)),
            (r"^(@.*)$", bygroups(None)),
        ],
        "actions": [
            (r"{(.|\n)+?}", bygroups(None)),
        ],
        "strings": [
            (r"'\w+?'", Keyword),
            (r'"\w+?"', Keyword),
            (r"'\W+?'", Text),
            (r'"\W+?"', Text),
        ],
        "variables": [
            (_name + _text_ws + "(=)", bygroups(None, None, None),),
            (_name + _text_ws + r"(\[[\w\d_\*]+?\])" + _text_ws + "(=)", bygroups(None, None, None, None, None),),
        ],
        "invalids": [
            (r"^(\s+\|\s+invalid_\w+\s*\n)", bygroups(None)),
            (r"^(\s+\|\s+incorrect_\w+\s*\n)", bygroups(None)),
            (r"^(#.*invalid syntax.*(?:.|\n)*)", bygroups(None),),
        ],
        "root": [
            include("invalids"),
            include("ws"),
            include("lookaheads"),
            include("metas"),
            include("actions"),
            include("strings"),
            include("variables"),
            (r"\b(?!(NULL|EXTRA))([A-Z_]+)\b\s*(?!\()", Text,),
            (
                r"^\s*" + _name + r"\s*" + r"(\[.*\])?" + r"\s*" + r"(\(.+\))?" + r"\s*(:)",
                bygroups(Name.Function, None, None, Punctuation),
            ),
            (_name, Name.Function),
            (r"[\||\.|\+|\*|\?]", Operator),
            (r"{|}|\(|\)|\[|\]", Punctuation),
            (r".", Text),
        ],
    }


def setup(app):
    lexers["peg"] = PEGLexer()
    return {"version": "1.0", "parallel_read_safe": True}