Starting from 2021-07-01, all LRZ GitLab users will be required to explicitly accept the GitLab Terms of Service. Please see the detailed information at https://doku.lrz.de/display/PUBLIC/GitLab and make sure that your projects conform to the requirements.

Commit 7ea1fb30 authored by di68kap's avatar di68kap
Browse files

- test_grammar function tested (and corrected)

parent fee343d4
...@@ -34,7 +34,11 @@ from .syntaxtree import Node, traverse, remove_enclosing_delimiters, reduce_sing ...@@ -34,7 +34,11 @@ from .syntaxtree import Node, traverse, remove_enclosing_delimiters, reduce_sing
from .versionnumber import __version__ from .versionnumber import __version__
__all__ = ['EBNFGrammar', __all__ = ['get_ebnf_scanner',
'get_ebnf_grammar',
'get_ebnf_transformer',
'get_ebnf_compiler',
'EBNFGrammar',
'EBNFTransformer', 'EBNFTransformer',
'EBNFCompilerError', 'EBNFCompilerError',
'EBNFCompiler', 'EBNFCompiler',
......
...@@ -56,7 +56,8 @@ try: ...@@ -56,7 +56,8 @@ try:
except ImportError: except ImportError:
import re import re
from .toolkit import is_logging, log_dir, logfile_basename, escape_re, sane_parser_name from .toolkit import is_logging, log_dir, logfile_basename, escape_re, sane_parser_name, \
compact_sexpr
from .syntaxtree import WHITESPACE_KEYWORD, TOKEN_KEYWORD, ZOMBIE_PARSER, Node, \ from .syntaxtree import WHITESPACE_KEYWORD, TOKEN_KEYWORD, ZOMBIE_PARSER, Node, \
mock_syntax_tree mock_syntax_tree
from DHParser.toolkit import load_if_file, error_messages from DHParser.toolkit import load_if_file, error_messages
...@@ -1090,24 +1091,29 @@ def test_grammar(test_suite, parser_factory, transformer_factory): ...@@ -1090,24 +1091,29 @@ def test_grammar(test_suite, parser_factory, transformer_factory):
for test_name, test_code in tests['match'].items(): for test_name, test_code in tests['match'].items():
cst = parser(test_code, parser_name) cst = parser(test_code, parser_name)
tests['__cst__'][test_name] = cst tests.setdefault('__cst__', {})[test_name] = cst
if cst.error_flag: if cst.error_flag:
errata.append("Test %s for parser %s : didn't match: \n%s" % errata.append('Match test "%s" for parser "%s" failed:\n\tExpr.: %s\n\t%s' %
(test_name, parser_name, (test_name, parser_name, '\n\t'.join(test_code.split('\n')),
error_messages(test_code, cst.collect_errors()))) '\n\t'.join(error_messages(test_code, cst.collect_errors()))))
elif "cst" in tests and mock_syntax_tree(tests["cst"][test_name]) != cst: elif "cst" in tests and mock_syntax_tree(tests["cst"][test_name]) != cst:
errata.append("Test %s for parser %s : wrong CST: \n%s" % errata.append('Concrete syntax tree test "%s" for parser "%s" failed:\n%s' %
(test_name, parser_name, cst.as_sexpr())) (test_name, parser_name, cst.as_sexpr()))
elif "ast" in tests: elif "ast" in tests:
ast = transform(cst) ast = copy.deepcopy(cst)
tests['__ast__'][test_name] = ast transform(ast)
if mock_syntax_tree(tests["ast"][test_name]) != ast: tests.setdefault('__ast__', {})[test_name] = ast
errata.append("Test %s for parser %s : wrong AST: \n%s" % compare = mock_syntax_tree(tests["ast"][test_name])
(test_name, parser_name, ast.as_sexpr())) if compare != ast:
errata.append('Abstract syntax tree test "%s" for parser "%s" failed:'
'\n\tExpr.: %s\n\tExpected: %s\n\tReceived: %s'
% (test_name, parser_name, '\n\t'.join(test_code.split('\n')),
compact_sexpr(ast.as_sexpr()),
compact_sexpr(compare.as_sexpr())))
for test_name, test_code in tests['fail'].items(): for test_name, test_code in tests['fail'].items():
cst = parser(test_code, parser_name) cst = parser(test_code, parser_name)
if not cst.error_flag: if not cst.error_flag:
errata.append("Test %s for parser %s : shouldn't have matched!" % errata.append('Fail test "%s" for parser "%s" yields match instead of '
(test_name, parser_name)) 'expected failure!' % (test_name, parser_name))
return errata return errata
...@@ -167,7 +167,8 @@ class Node: ...@@ -167,7 +167,8 @@ class Node:
return str(self.result) return str(self.result)
def __eq__(self, other): def __eq__(self, other):
return str(self.parser) == str(other.parser) and self.result == other.result # return str(self.parser) == str(other.parser) and self.result == other.result
return self.tag_name == other.tag_name and self.result == other.result
def __hash__(self): def __hash__(self):
return hash((str(self.parser), )) return hash((str(self.parser), ))
...@@ -421,7 +422,8 @@ def mock_syntax_tree(sexpr): ...@@ -421,7 +422,8 @@ def mock_syntax_tree(sexpr):
def next_block(s): def next_block(s):
s = s.strip() s = s.strip()
while s[0] != ')': while s[0] != ')':
assert s[0] == '(', s if s[0] != '(': raise ValueError('"(" expected, not ' + s[:10])
# assert s[0] == '(', s
level = 1; level = 1;
i = 1 i = 1
while level > 0: while level > 0:
...@@ -434,7 +436,8 @@ def mock_syntax_tree(sexpr): ...@@ -434,7 +436,8 @@ def mock_syntax_tree(sexpr):
s = s[i:].strip() s = s[i:].strip()
sexpr = sexpr.strip() sexpr = sexpr.strip()
assert sexpr[0] == '(', sexpr if sexpr[0] != '(': raise ValueError('"(" expected, not ' + sexpr[:10])
# assert sexpr[0] == '(', sexpr
sexpr = sexpr[1:].strip() sexpr = sexpr[1:].strip()
m = re.match('\w+', sexpr) m = re.match('\w+', sexpr)
name = sexpr[:m.end()] name = sexpr[:m.end()]
......
...@@ -26,7 +26,7 @@ sys.path.extend(['../', './']) ...@@ -26,7 +26,7 @@ sys.path.extend(['../', './'])
from DHParser.toolkit import is_logging, compile_python_object from DHParser.toolkit import is_logging, compile_python_object
from DHParser.syntaxtree import no_operation, traverse, remove_expendables, \ from DHParser.syntaxtree import no_operation, traverse, remove_expendables, \
replace_by_single_child, reduce_single_child, flatten, TOKEN_KEYWORD replace_by_single_child, reduce_single_child, flatten, TOKEN_KEYWORD
from DHParser.parsers import compile_source from DHParser.parsers import compile_source, test_grammar
from DHParser.ebnf import get_ebnf_grammar, get_ebnf_transformer, get_ebnf_compiler from DHParser.ebnf import get_ebnf_grammar, get_ebnf_transformer, get_ebnf_compiler
from DHParser.dsl import parser_factory, DHPARSER_IMPORTS from DHParser.dsl import parser_factory, DHPARSER_IMPORTS
...@@ -62,12 +62,56 @@ class TestGrammarTest: ...@@ -62,12 +62,56 @@ class TestGrammarTest:
2: "314", 2: "314",
}, },
"fail": { "fail": {
1: "21F", 3: "21F",
2: "G123" 4: "G123"
}
},
"term": {
"match": {
1: "4 * 5",
2: "20 / 4",
3: "20 / 4 * 3"
},
"ast": {
1: "(term (factor 4) (TOKEN__ *) (factor 5))",
2: "(term (factor 20) (TOKEN__ /) (factor 4))",
3: "(term (term (factor 20) (TOKEN__ /) (factor 4)) (TOKEN__ *) (factor 3))"
},
"fail": {
4: "4 + 5",
5: "20 / 4 - 3"
}
}
}
failure_cases = {
"term": {
"match": {
1: "4 + 5", # error: this should fail
2: "20 / 4",
3: "20 / 4 * 3"
},
"ast": {
1: "(term (factor 4) (TOKEN__ *) (factor 5))",
2: "(term (factor 20) (TOKEN__ /) (factor 4))",
3: "(term (term (factor 19) (TOKEN__ /) (factor 4)) (TOKEN__ *) (factor 3))" # error 19 != 20
},
"fail": {
4: "4 * 5", # error: this should match
5: "20 / 4 - 3"
} }
} }
} }
def test_test_grammar(self):
parser_fac = parser_factory(ARITHMETIC_EBNF)
trans_fac = lambda : ARITHMETIC_EBNFTransform
errata = test_grammar(self.cases, parser_fac, trans_fac)
assert not errata
errata = test_grammar(self.failure_cases, parser_fac, trans_fac)
# for e in errata:
# print(e)
assert len(errata) == 3
class TestInfiLoopsAndRecursion: class TestInfiLoopsAndRecursion:
def test_direct_left_recursion(self): def test_direct_left_recursion(self):
......
...@@ -24,7 +24,9 @@ import sys ...@@ -24,7 +24,9 @@ import sys
sys.path.extend(['../', './']) sys.path.extend(['../', './'])
from DHParser.toolkit import compact_sexpr from DHParser.toolkit import compact_sexpr
from DHParser.syntaxtree import traverse, mock_syntax_tree from DHParser.syntaxtree import traverse, mock_syntax_tree, reduce_single_child, \
replace_by_single_child, flatten, remove_expendables, TOKEN_KEYWORD
from DHParser.dsl import parser_factory
class MockParser: class MockParser:
...@@ -86,10 +88,23 @@ class TestNode: ...@@ -86,10 +88,23 @@ class TestNode:
assert len(found) == 2 assert len(found) == 2
assert found[0].result == 'x' and found[1].result == 'y' assert found[0].result == 'x' and found[1].result == 'y'
def test_equality(self): def test_equality1(self):
assert self.unique_tree == self.unique_tree assert self.unique_tree == self.unique_tree
assert self.recurr_tree != self.unique_tree assert self.recurr_tree != self.unique_tree
assert mock_syntax_tree('(a (b c))') != mock_syntax_tree('(a (b d))') assert mock_syntax_tree('(a (b c))') != mock_syntax_tree('(a (b d))')
assert mock_syntax_tree('(a (b c))') == mock_syntax_tree('(a (b c))')
def test_equality2(self):
ebnf = 'term = term ("*"|"/") factor | factor\nfactor = /[0-9]+/~'
att = {"term": [replace_by_single_child, flatten],
"factor": [remove_expendables, reduce_single_child],
(TOKEN_KEYWORD): [remove_expendables, reduce_single_child],
"": [remove_expendables, replace_by_single_child]}
parser = parser_factory(ebnf)()
tree = parser("20 / 4 * 3")
traverse(tree, att)
compare_tree = mock_syntax_tree("(term (term (factor 20) (TOKEN__ /) (factor 4)) (TOKEN__ *) (factor 3))")
assert tree == compare_tree
def test_copy(self): def test_copy(self):
cpy = copy.deepcopy(self.unique_tree) cpy = copy.deepcopy(self.unique_tree)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment