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")
|