| OLD | NEW |
| (Empty) |
| 1 #!/usr/bin/python | |
| 2 # Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | |
| 3 # for details. All rights reserved. Use of this source code is governed by a | |
| 4 # BSD-style license that can be found in the LICENSE file. | |
| 5 | |
| 6 import logging.config | |
| 7 import pprint | |
| 8 import re | |
| 9 import sys | |
| 10 import unittest | |
| 11 from pegparser import * | |
| 12 | |
| 13 | |
| 14 class PegParserTestCase(unittest.TestCase): | |
| 15 | |
| 16 def _run_test(self, grammar, text, expected, | |
| 17 strings_are_tokens=False, whitespace_rule=None): | |
| 18 """Utility for running a parser test and comparing results. | |
| 19 | |
| 20 Program exits (sys.exit) if expected does not match actual. | |
| 21 | |
| 22 Args: | |
| 23 grammar -- the root rule to be used by the parser. | |
| 24 text -- the text to parse. | |
| 25 expected -- the expected abstract syntax tree. None means | |
| 26 failure is expected. | |
| 27 strings_are_tokens -- whether strings are treated as tokens. | |
| 28 whitespace_rule -- the rule used for matching whitespace. | |
| 29 Default is None, which means that no whitespace is tolerated. | |
| 30 """ | |
| 31 parser = PegParser(grammar, whitespace_rule, | |
| 32 strings_are_tokens=strings_are_tokens) | |
| 33 actual = None | |
| 34 error = None | |
| 35 try: | |
| 36 actual = parser.parse(text) | |
| 37 except SyntaxError, e: | |
| 38 error = e | |
| 39 pass | |
| 40 | |
| 41 if actual != expected: | |
| 42 msg = ''' | |
| 43 CONTENT: | |
| 44 %s | |
| 45 EXPECTED: | |
| 46 %s | |
| 47 ACTUAL: | |
| 48 %s | |
| 49 ERROR: %s''' % (text, pprint.pformat(expected), pprint.pformat(actual), error) | |
| 50 self.fail(msg) | |
| 51 | |
| 52 def test_sequence(self): | |
| 53 sequence = SEQUENCE('A', 'BB', 'C') | |
| 54 self._run_test(grammar=sequence, text='ABBC', expected=['A', 'BB', 'C']) | |
| 55 self._run_test(grammar=sequence, text='BBAC', expected=None) | |
| 56 # Syntax Sugar | |
| 57 sequence = ['A', 'BB', 'C'] | |
| 58 self._run_test(grammar=sequence, text='ABBC', expected=['A', 'BB', 'C']) | |
| 59 self._run_test(grammar=sequence, text='BBAC', expected=None) | |
| 60 | |
| 61 def test_regex(self): | |
| 62 regex = re.compile(r'[A-Za-z]*') | |
| 63 self._run_test(grammar=regex, text='AaBb', expected='AaBb') | |
| 64 self._run_test(grammar=regex, text='0AaBb', expected=None) | |
| 65 self._run_test(grammar=regex, text='Aa0Bb', expected=None) | |
| 66 | |
| 67 def test_function(self): | |
| 68 def Func(): | |
| 69 return 'ABC' | |
| 70 self._run_test(grammar=Func, text='ABC', expected=('Func', 'ABC')) | |
| 71 self._run_test(grammar=Func, text='XYZ', expected=None) | |
| 72 | |
| 73 def test_function_label(self): | |
| 74 def func(): | |
| 75 return 'ABC' | |
| 76 | |
| 77 def _func(): | |
| 78 return 'ABC' | |
| 79 | |
| 80 self._run_test(grammar=func, text='ABC', expected=('func', 'ABC')) | |
| 81 self._run_test(grammar=_func, text='ABC', expected='ABC') | |
| 82 | |
| 83 def test_label(self): | |
| 84 sequence = [TOKEN('def'), LABEL('funcName', re.compile(r'[a-z0-9]*')), | |
| 85 TOKEN('():')] | |
| 86 self._run_test(grammar=sequence, text='def f1():', | |
| 87 whitespace_rule=' ', expected=[('funcName', 'f1')]) | |
| 88 self._run_test(grammar=sequence, text='def f2():', | |
| 89 whitespace_rule=' ', expected=[('funcName', 'f2')]) | |
| 90 | |
| 91 def test_or(self): | |
| 92 grammer = OR('A', 'B') | |
| 93 self._run_test(grammar=grammer, text='A', expected='A') | |
| 94 self._run_test(grammar=grammer, text='B', expected='B') | |
| 95 self._run_test(grammar=grammer, text='C', expected=None) | |
| 96 | |
| 97 def test_maybe(self): | |
| 98 seq = ['A', MAYBE('B'), 'C'] | |
| 99 self._run_test(grammar=seq, text='ABC', expected=['A', 'B', 'C']) | |
| 100 self._run_test(grammar=seq, text='ADC', expected=None) | |
| 101 self._run_test(grammar=seq, text='AC', expected=['A', 'C']) | |
| 102 self._run_test(grammar=seq, text='AB', expected=None) | |
| 103 | |
| 104 def test_many(self): | |
| 105 seq = ['A', MANY('B'), 'C'] | |
| 106 self._run_test(grammar=seq, text='ABC', expected=['A', 'B', 'C']) | |
| 107 self._run_test(grammar=seq, text='ABBBBC', | |
| 108 expected=['A', 'B', 'B', 'B', 'B', 'C']) | |
| 109 self._run_test(grammar=seq, text='AC', expected=None) | |
| 110 | |
| 111 def test_many_with_separator(self): | |
| 112 letter = OR('A', 'B', 'C') | |
| 113 | |
| 114 def _gram(): | |
| 115 return [letter, MAYBE([TOKEN(','), _gram])] | |
| 116 | |
| 117 self._run_test(grammar=_gram, text='A,B,C,B', | |
| 118 expected=['A', 'B', 'C', 'B']) | |
| 119 self._run_test(grammar=_gram, text='A B C', expected=None) | |
| 120 shortergrammar = MANY(letter, TOKEN(',')) | |
| 121 self._run_test(grammar=shortergrammar, text='A,B,C,B', | |
| 122 expected=['A', 'B', 'C', 'B']) | |
| 123 self._run_test(grammar=shortergrammar, text='A B C', expected=None) | |
| 124 | |
| 125 def test_raise(self): | |
| 126 self._run_test(grammar=['A', 'B'], text='AB', | |
| 127 expected=['A', 'B']) | |
| 128 try: | |
| 129 self._run_test(grammar=['A', 'B', RAISE('test')], text='AB', | |
| 130 expected=None) | |
| 131 print 'Expected RuntimeError' | |
| 132 sys.exit(-1) | |
| 133 except RuntimeError, e: | |
| 134 return | |
| 135 | |
| 136 def test_whitespace(self): | |
| 137 gram = MANY('A') | |
| 138 self._run_test(grammar=gram, text='A A A', expected=None) | |
| 139 self._run_test(grammar=gram, whitespace_rule=' ', text='A A A', | |
| 140 expected=['A', 'A', 'A']) | |
| 141 | |
| 142 def test_math_expression_syntax(self): | |
| 143 operator = LABEL('op', OR('+', '-', '/', '*')) | |
| 144 literal = LABEL('num', re.compile(r'[0-9]+')) | |
| 145 | |
| 146 def _exp(): | |
| 147 return MANY(OR(literal, [TOKEN('('), _exp, TOKEN(')')]), | |
| 148 separator=operator) | |
| 149 | |
| 150 self._run_test(grammar=_exp, | |
| 151 text='(1-2)+3*((4*5)*6)+(7+8/9)-10', | |
| 152 expected=[[('num', '1'), ('op', '-'), ('num', '2')], | |
| 153 ('op', '+'), | |
| 154 ('num', '3'), | |
| 155 ('op', '*'), | |
| 156 [[('num', '4'), ('op', '*'), ('num', '5')], | |
| 157 ('op', '*'), ('num', '6')], | |
| 158 ('op', '+'), | |
| 159 [('num', '7'), ('op', '+'), ('num', '8'), | |
| 160 ('op', '/'), ('num', '9')], | |
| 161 ('op', '-'), | |
| 162 ('num', '10')]) | |
| 163 | |
| 164 def test_mini_language(self): | |
| 165 def name(): | |
| 166 return re.compile(r'[a-z]+') | |
| 167 | |
| 168 def var_decl(): | |
| 169 return ['var', name, ';'] | |
| 170 | |
| 171 def func_invoke(): | |
| 172 return [name, '(', ')', ';'] | |
| 173 | |
| 174 def func_body(): | |
| 175 return MANY(OR(var_decl, func_invoke)) | |
| 176 | |
| 177 def func_decl(): | |
| 178 return ['function', name, '(', ')', '{', func_body, '}'] | |
| 179 | |
| 180 def args(): | |
| 181 return MANY(name, ',') | |
| 182 | |
| 183 def program(): | |
| 184 return MANY(OR(var_decl, func_decl)) | |
| 185 | |
| 186 self._run_test(grammar=program, | |
| 187 whitespace_rule=OR('\n', ' '), | |
| 188 strings_are_tokens=True, | |
| 189 text='var x;\nfunction f(){\n var y;\n g();\n}\n', | |
| 190 expected=('program',[ | |
| 191 ('var_decl', [('name', 'x')]), | |
| 192 ('func_decl', [('name', 'f'), ('func_body', [ | |
| 193 ('var_decl', [('name', 'y')]), | |
| 194 ('func_invoke', [('name', 'g')])])])])) | |
| 195 | |
| 196 | |
| 197 if __name__ == "__main__": | |
| 198 logging.config.fileConfig("logging.conf") | |
| 199 if __name__ == '__main__': | |
| 200 unittest.main() | |
| OLD | NEW |