diff --git a/DHParser/syntaxtree.py b/DHParser/syntaxtree.py index da0ffd35958a7e9efbd08772f5e687e4322f8c25..c2ad075f7cad1dd5f26358a0e37a15a2afd31099 100644 --- a/DHParser/syntaxtree.py +++ b/DHParser/syntaxtree.py @@ -22,6 +22,8 @@ permissions and limitations under the License. import itertools import os from functools import partial + + try: import regex as re except ImportError: @@ -56,7 +58,19 @@ __all__ = ['WHITESPACE_KEYWORD', 'assert_content'] -class ZombieParser: +class MockParser: + def __init__(self, name=''): + self.name = name + + def __str__(self): + return self.name or self.__class__.__name__ + + def __call__(self, text): + """Better call Saul ;-)""" + return None, text + + +class ZombieParser(MockParser): """ Serves as a substitute for a Parser instance. @@ -69,9 +83,9 @@ class ZombieParser: alive = False def __init__(self): + super(ZombieParser, self).__init__("ZOMBIE") assert not self.__class__.alive, "There can be only one!" assert self.__class__ == ZombieParser, "No derivatives, please!" - self.name = "ZOMBIE" self.__class__.alive = True def __copy__(self): @@ -80,13 +94,6 @@ class ZombieParser: def __deepcopy__(self, memo): return self - def __str__(self): - return self.name - - def __call__(self, text): - """Better call Saul ;-)""" - return None, text - ZOMBIE_PARSER = ZombieParser() @@ -381,6 +388,48 @@ class Node: return nav(path.split('/')) +def mock_syntax_tree(sexpr): + """Generates a tree of nodes from an S-expression. + + Example: + >>> mock_syntax_tree("(a (b c))").as_sexpr() + (a + (b + c + ) + ) + """ + def next_block(s): + s = s.strip() + while s[0] != ')': + assert s[0] == '(', s + level = 1; + i = 1 + while level > 0: + if s[i] == '(': + level += 1 + elif s[i] == ')': + level -= 1 + i += 1 + yield s[:i] + s = s[i:].strip() + + sexpr = sexpr.strip() + assert sexpr[0] == '(', sexpr + sexpr = sexpr[1:].strip() + m = re.match('\w+', sexpr) + name = sexpr[:m.end()] + sexpr = sexpr[m.end():].strip() + if sexpr[0] == '(': + result = tuple(mock_syntax_tree(block) for block in next_block(sexpr)) + else: + m = re.match('\w+', sexpr) + result = sexpr[:m.end()] + sexpr = sexpr[m.end():].strip() + assert sexpr[0] == ')', sexpr + return Node(MockParser(name), result) + + ######################################################################## # # syntax tree transformation functions diff --git a/tests/test_dsl.py b/tests/test_dsl.py index 896b03a3650280faafdbb0a90dfed1fc72bba0fc..13462f9700cdc6dc3138dd0166c1bc5b10da488c 100644 --- a/tests/test_dsl.py +++ b/tests/test_dsl.py @@ -20,4 +20,31 @@ See the License for the specific language governing permissions and limitations under the License. """ +import os +import sys +from DHParser.dsl import run_compiler +class TestCompilerGeneration: + trivial_lang = """ + text = { word | WSPC } + word = /\w+/ + WSPC = /\s*/ + """ + trivial_text = """Es war ein König in Thule.""" + + + def setup(self): + + +if (not os.path.exists('PopRetrieve_compiler.py') or + suite_outdated('PopRetrieve_compiler.py', 'PopRetrieve.ebnf')): + print("recompiling PopRetrieve parser") + errors = run_compiler("PopRetrieve.ebnf") + if errors: + print('\n\n'.join(errors)) + sys.exit(1) + + +if __name__ == "__main__": + from run import runner + runner("", globals()) \ No newline at end of file diff --git a/tests/test_syntaxtree.py b/tests/test_syntaxtree.py index acd080c048ae35480b5fca18bd47983794a12153..c4d6ba3571f306f4de632e6f9eb3adc4ecbef8c8 100644 --- a/tests/test_syntaxtree.py +++ b/tests/test_syntaxtree.py @@ -20,14 +20,13 @@ limitations under the License. """ import os -import re import sys sys.path.append(os.path.abspath('../../')) from DHParser.toolkit import compact_sexpr -from DHParser.syntaxtree import Node, traverse +from DHParser.syntaxtree import traverse, mock_syntax_tree -class DummyParser: +class MockParser: def __init__(self, name=''): self.name = name @@ -38,47 +37,6 @@ class DummyParser: return None, text -def from_sexpr(s): - """Generates a tree of nodes from an S-expression. - - Example: - >>> from_sexpr("(a (b c))").as_sexpr() - (a - (b - c - ) - ) - """ - def next_block(s): - s = s.strip() - while s[0] != ')': - assert s[0] == '(', s - level = 1; i = 1 - while level > 0: - if s[i] == '(': - level += 1 - elif s[i] == ')': - level -= 1 - i += 1 - yield s[:i] - s = s[i:].strip() - - s = s.strip() - assert s[0] == '(', s - s = s[1:].strip() - m = re.match('\w+', s) - name = s[:m.end()] - s = s[m.end():].strip() - if s[0] == '(': - result = tuple(from_sexpr(block) for block in next_block(s)) - else: - m = re.match('\w+', s) - result = s[:m.end()] - s = s[m.end():].strip() - assert s[0] == ')', s - return Node(DummyParser(name), result) - - class TestSExpr: """ Tests for S-expression handling. @@ -88,7 +46,7 @@ class TestSExpr: def test_selftest_from_sexpr(self): sexpr = '(a (b c) (d e) (f (g h)))' - tree = from_sexpr(sexpr) + tree = mock_syntax_tree(sexpr) assert compact_sexpr(tree.as_sexpr(prettyprint=False)) == sexpr @@ -98,9 +56,9 @@ class TestNode: """ def setup(self): self.unique_nodes_sexpr = '(a (b c) (d e) (f (g h)))' - self.unique_tree = from_sexpr(self.unique_nodes_sexpr) + self.unique_tree = mock_syntax_tree(self.unique_nodes_sexpr) self.recurring_nodes_sexpr = '(a (b x) (c (d e) (b y)))' - self.recurr_tree = from_sexpr(self.recurring_nodes_sexpr) + self.recurr_tree = mock_syntax_tree(self.recurring_nodes_sexpr) def test_str(self): assert str(self.unique_tree) == "ceh" @@ -117,7 +75,7 @@ class TestNode: class TestErrorHandling: def test_error_flag_propagation(self): - tree = from_sexpr('(a (b c) (d (e (f (g h)))))') + tree = mock_syntax_tree('(a (b c) (d (e (f (g h)))))') def find_h(node): if node.result == "h":