File: test_metaparser.py

package info (click to toggle)
pypy3 7.0.0%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 111,848 kB
  • sloc: python: 1,291,746; ansic: 74,281; asm: 5,187; cpp: 3,017; sh: 2,533; makefile: 544; xml: 243; lisp: 45; csh: 21; awk: 4
file content (112 lines) | stat: -rw-r--r-- 3,622 bytes parent folder | download | duplicates (4)
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import py
import os
import glob
import tokenize
import token
import StringIO
from pypy.interpreter.pyparser.metaparser import ParserGenerator, PgenError
from pypy.interpreter.pyparser.pygram import PythonGrammar
from pypy.interpreter.pyparser import parser


class MyGrammar(parser.Grammar):
    TOKENS = token.__dict__
    OPERATOR_MAP = {
        "+" : token.OP,
        "-" : token.OP,
        }
    KEYWORD_TOKEN = token.NAME


class TestParserGenerator:

    def gram_for(self, grammar_source):
        p = ParserGenerator(grammar_source + "\n")
        return p.build_grammar(MyGrammar)

    def test_multiple_rules(self):
        g = self.gram_for("foo: NAME bar\nbar: STRING")
        assert len(g.dfas) == 2
        assert g.start == g.symbol_ids["foo"]

    def test_simple(self):
        g = self.gram_for("eval: NAME\n")
        assert len(g.dfas) == 1
        eval_sym = g.symbol_ids["eval"]
        assert g.start == eval_sym
        dfa = g.dfas[eval_sym - 256]
        assert dfa.states == [([(1, 1)], False), ([], True)]
        assert g.labels[0] == 0

    def test_load_python_grammars(self):
        gram_pat = os.path.join(os.path.dirname(__file__), "..", "data",
                                "Grammar*")
        for gram_file in glob.glob(gram_pat):
            fp = open(gram_file, "r")
            try:
                ParserGenerator(fp.read()).build_grammar(PythonGrammar)
            finally:
                fp.close()

    def test_items(self):
        g = self.gram_for("foo: NAME STRING OP '+'")
        assert len(g.dfas) == 1
        states = g.dfas[g.symbol_ids["foo"] - 256].states
        last = states[0][0][0][1]
        for state in states[1:-1]:
            assert last < state[0][0][1]
            last = state[0][0][1]

    def test_alternatives(self):
        g = self.gram_for("foo: STRING | OP")
        assert len(g.dfas) == 1

    def test_optional(self):
        g = self.gram_for("foo: [NAME]")

    def test_grouping(self):
        g = self.gram_for("foo: (NAME | STRING) OP")

    def test_keyword(self):
        g = self.gram_for("foo: 'some_keyword' 'for'")
        assert len(g.keyword_ids) == 2
        assert len(g.token_ids) == 0

    def test_token(self):
        g = self.gram_for("foo: NAME")
        assert len(g.token_ids) == 1

    def test_operator(self):
        g = self.gram_for("add: NUMBER '+' NUMBER")
        assert len(g.keyword_ids) == 0
        assert len(g.token_ids) == 2

        exc = py.test.raises(PgenError, self.gram_for, "add: '/'").value
        assert str(exc) == "no such operator: '/'"

    def test_symbol(self):
        g = self.gram_for("foo: some_other_rule\nsome_other_rule: NAME")
        assert len(g.dfas) == 2
        assert len(g.labels) == 3

        exc = py.test.raises(PgenError, self.gram_for, "foo: no_rule").value
        assert str(exc) == "no such rule: 'no_rule'"

    def test_repeaters(self):
        g1 = self.gram_for("foo: NAME+")
        g2 = self.gram_for("foo: NAME*")
        assert g1.dfas != g2.dfas

        g = self.gram_for("foo: (NAME | STRING)*")
        g = self.gram_for("foo: (NAME | STRING)+")

    def test_error(self):
        exc = py.test.raises(PgenError, self.gram_for, "hi").value
        assert str(exc) == "expected token OP but got NEWLINE"
        assert exc.location == ((1, 2), (1, 3), "hi\n")
        exc = py.test.raises(PgenError, self.gram_for, "hi+").value
        assert str(exc) == "expected ':' but got '+'"
        assert exc.location == ((1, 2), (1, 3), "hi+\n")

    def test_comments_and_whitespace(self):
        self.gram_for("\n\n# comment\nrule: NAME # comment")