880f4d814a
Review URL: https://chromiumcodereview.appspot.com//10913125 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@12082 260f80e4-7a28-3924-810f-c04153c831b5
201 lines
6.2 KiB
Python
Executable File
201 lines
6.2 KiB
Python
Executable File
#!/usr/bin/python
|
|
# Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
|
|
# for details. All rights reserved. Use of this source code is governed by a
|
|
# BSD-style license that can be found in the LICENSE file.
|
|
|
|
import logging.config
|
|
import pprint
|
|
import re
|
|
import sys
|
|
import unittest
|
|
from pegparser import *
|
|
|
|
|
|
class PegParserTestCase(unittest.TestCase):
|
|
|
|
def _run_test(self, grammar, text, expected,
|
|
strings_are_tokens=False, whitespace_rule=None):
|
|
"""Utility for running a parser test and comparing results.
|
|
|
|
Program exits (sys.exit) if expected does not match actual.
|
|
|
|
Args:
|
|
grammar -- the root rule to be used by the parser.
|
|
text -- the text to parse.
|
|
expected -- the expected abstract syntax tree. None means
|
|
failure is expected.
|
|
strings_are_tokens -- whether strings are treated as tokens.
|
|
whitespace_rule -- the rule used for matching whitespace.
|
|
Default is None, which means that no whitespace is tolerated.
|
|
"""
|
|
parser = PegParser(grammar, whitespace_rule,
|
|
strings_are_tokens=strings_are_tokens)
|
|
actual = None
|
|
error = None
|
|
try:
|
|
actual = parser.parse(text)
|
|
except SyntaxError, e:
|
|
error = e
|
|
pass
|
|
|
|
if actual != expected:
|
|
msg = '''
|
|
CONTENT:
|
|
%s
|
|
EXPECTED:
|
|
%s
|
|
ACTUAL:
|
|
%s
|
|
ERROR: %s''' % (text, pprint.pformat(expected), pprint.pformat(actual), error)
|
|
self.fail(msg)
|
|
|
|
def test_sequence(self):
|
|
sequence = SEQUENCE('A', 'BB', 'C')
|
|
self._run_test(grammar=sequence, text='ABBC', expected=['A', 'BB', 'C'])
|
|
self._run_test(grammar=sequence, text='BBAC', expected=None)
|
|
# Syntax Sugar
|
|
sequence = ['A', 'BB', 'C']
|
|
self._run_test(grammar=sequence, text='ABBC', expected=['A', 'BB', 'C'])
|
|
self._run_test(grammar=sequence, text='BBAC', expected=None)
|
|
|
|
def test_regex(self):
|
|
regex = re.compile(r'[A-Za-z]*')
|
|
self._run_test(grammar=regex, text='AaBb', expected='AaBb')
|
|
self._run_test(grammar=regex, text='0AaBb', expected=None)
|
|
self._run_test(grammar=regex, text='Aa0Bb', expected=None)
|
|
|
|
def test_function(self):
|
|
def Func():
|
|
return 'ABC'
|
|
self._run_test(grammar=Func, text='ABC', expected=('Func', 'ABC'))
|
|
self._run_test(grammar=Func, text='XYZ', expected=None)
|
|
|
|
def test_function_label(self):
|
|
def func():
|
|
return 'ABC'
|
|
|
|
def _func():
|
|
return 'ABC'
|
|
|
|
self._run_test(grammar=func, text='ABC', expected=('func', 'ABC'))
|
|
self._run_test(grammar=_func, text='ABC', expected='ABC')
|
|
|
|
def test_label(self):
|
|
sequence = [TOKEN('def'), LABEL('funcName', re.compile(r'[a-z0-9]*')),
|
|
TOKEN('():')]
|
|
self._run_test(grammar=sequence, text='def f1():',
|
|
whitespace_rule=' ', expected=[('funcName', 'f1')])
|
|
self._run_test(grammar=sequence, text='def f2():',
|
|
whitespace_rule=' ', expected=[('funcName', 'f2')])
|
|
|
|
def test_or(self):
|
|
grammer = OR('A', 'B')
|
|
self._run_test(grammar=grammer, text='A', expected='A')
|
|
self._run_test(grammar=grammer, text='B', expected='B')
|
|
self._run_test(grammar=grammer, text='C', expected=None)
|
|
|
|
def test_maybe(self):
|
|
seq = ['A', MAYBE('B'), 'C']
|
|
self._run_test(grammar=seq, text='ABC', expected=['A', 'B', 'C'])
|
|
self._run_test(grammar=seq, text='ADC', expected=None)
|
|
self._run_test(grammar=seq, text='AC', expected=['A', 'C'])
|
|
self._run_test(grammar=seq, text='AB', expected=None)
|
|
|
|
def test_many(self):
|
|
seq = ['A', MANY('B'), 'C']
|
|
self._run_test(grammar=seq, text='ABC', expected=['A', 'B', 'C'])
|
|
self._run_test(grammar=seq, text='ABBBBC',
|
|
expected=['A', 'B', 'B', 'B', 'B', 'C'])
|
|
self._run_test(grammar=seq, text='AC', expected=None)
|
|
|
|
def test_many_with_separator(self):
|
|
letter = OR('A', 'B', 'C')
|
|
|
|
def _gram():
|
|
return [letter, MAYBE([TOKEN(','), _gram])]
|
|
|
|
self._run_test(grammar=_gram, text='A,B,C,B',
|
|
expected=['A', 'B', 'C', 'B'])
|
|
self._run_test(grammar=_gram, text='A B C', expected=None)
|
|
shortergrammar = MANY(letter, TOKEN(','))
|
|
self._run_test(grammar=shortergrammar, text='A,B,C,B',
|
|
expected=['A', 'B', 'C', 'B'])
|
|
self._run_test(grammar=shortergrammar, text='A B C', expected=None)
|
|
|
|
def test_raise(self):
|
|
self._run_test(grammar=['A', 'B'], text='AB',
|
|
expected=['A', 'B'])
|
|
try:
|
|
self._run_test(grammar=['A', 'B', RAISE('test')], text='AB',
|
|
expected=None)
|
|
print 'Expected RuntimeError'
|
|
sys.exit(-1)
|
|
except RuntimeError, e:
|
|
return
|
|
|
|
def test_whitespace(self):
|
|
gram = MANY('A')
|
|
self._run_test(grammar=gram, text='A A A', expected=None)
|
|
self._run_test(grammar=gram, whitespace_rule=' ', text='A A A',
|
|
expected=['A', 'A', 'A'])
|
|
|
|
def test_math_expression_syntax(self):
|
|
operator = LABEL('op', OR('+', '-', '/', '*'))
|
|
literal = LABEL('num', re.compile(r'[0-9]+'))
|
|
|
|
def _exp():
|
|
return MANY(OR(literal, [TOKEN('('), _exp, TOKEN(')')]),
|
|
separator=operator)
|
|
|
|
self._run_test(grammar=_exp,
|
|
text='(1-2)+3*((4*5)*6)+(7+8/9)-10',
|
|
expected=[[('num', '1'), ('op', '-'), ('num', '2')],
|
|
('op', '+'),
|
|
('num', '3'),
|
|
('op', '*'),
|
|
[[('num', '4'), ('op', '*'), ('num', '5')],
|
|
('op', '*'), ('num', '6')],
|
|
('op', '+'),
|
|
[('num', '7'), ('op', '+'), ('num', '8'),
|
|
('op', '/'), ('num', '9')],
|
|
('op', '-'),
|
|
('num', '10')])
|
|
|
|
def test_mini_language(self):
|
|
def name():
|
|
return re.compile(r'[a-z]+')
|
|
|
|
def var_decl():
|
|
return ['var', name, ';']
|
|
|
|
def func_invoke():
|
|
return [name, '(', ')', ';']
|
|
|
|
def func_body():
|
|
return MANY(OR(var_decl, func_invoke))
|
|
|
|
def func_decl():
|
|
return ['function', name, '(', ')', '{', func_body, '}']
|
|
|
|
def args():
|
|
return MANY(name, ',')
|
|
|
|
def program():
|
|
return MANY(OR(var_decl, func_decl))
|
|
|
|
self._run_test(grammar=program,
|
|
whitespace_rule=OR('\n', ' '),
|
|
strings_are_tokens=True,
|
|
text='var x;\nfunction f(){\n var y;\n g();\n}\n',
|
|
expected=('program',[
|
|
('var_decl', [('name', 'x')]),
|
|
('func_decl', [('name', 'f'), ('func_body', [
|
|
('var_decl', [('name', 'y')]),
|
|
('func_invoke', [('name', 'g')])])])]))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
logging.config.fileConfig("logging.conf")
|
|
if __name__ == '__main__':
|
|
unittest.main()
|