test_EBNFcompiler.py 5.11 KB
Newer Older
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
#!/usr/bin/python3

"""test_EBNFcompiler.py - tests of the EBNFcompiler-module of DHParser 
                             

Author: Eckhart Arnold <arnold@badw.de>

Copyright 2017 Bavarian Academy of Sciences and Humanities

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""

import os
import sys
sys.path.append(os.path.abspath('../../'))
26
27
28
from DHParser.syntaxtree import traverse
from DHParser.parsercombinators import full_compilation
from DHParser.EBNFcompiler import EBNFGrammar, EBNF_ASTPipeline, EBNFCompiler
29
from DHParser.DSLsupport import compileEBNF
30
31
32
33
34


WRITE_LOGS = True


35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
class TestDirectives:
    mini_language = """
        expression =  term  { ("+" | "-") term }
        term       =  factor  { ("*" | "/") factor }
        factor     =  constant | "("  expression  ")"
        constant   =  digit { digit } [ //~ ]
        digit      = /0/ | /1/ | /2/ | /3/ | /4/ | /5/ | /6/ | /7/ | /8/ | /9/ 
        """

    def test_whitespace_linefeed(self):
        lang = "@ whitespace = linefeed\n" + self.mini_language
        MinilangParser = compileEBNF(lang)
        parser = MinilangParser()
        assert parser
        syntax_tree = parser.parse("3 + 4 * 12")
Eckhart Arnold's avatar
Eckhart Arnold committed
50
        parser.log_parsing_history("WSP")
51
52
        assert not syntax_tree.collect_errors()
        syntax_tree = parser.parse("3 + 4 \n * 12")
Eckhart Arnold's avatar
Eckhart Arnold committed
53
        parser.log_parsing_history("WSPLF")
54
55
56
57
58
59
60
61
62
63
64
        assert not syntax_tree.collect_errors()

    def test_whitespace_standard(self):
        lang = "@ whitespace = standard\n" + self.mini_language
        parser = compileEBNF(lang)()
        assert parser
        syntax_tree = parser.parse("3 + 4 * 12")
        assert not syntax_tree.collect_errors()
        syntax_tree = parser.parse("3 + 4 \n * 12")
        assert syntax_tree.collect_errors()

65

66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
class TestPopRetrieve:
    mini_language = """
        document       = { text | codeblock }
        codeblock      = delimiter { text | (!:delimiter delimiter_sign) } ::delimiter
        delimiter      = delimiter_sign
        delimiter_sign = /`+/
        text           = /[^`]+/ 
        """

    def setup(self):
        self.minilang_parser = compileEBNF(self.mini_language)()

    def test_compile_mini_language(self):
        assert self.minilang_parser

    def test_single_line(self):
        teststr = "Anfang ```code block `` <- keine Ende-Zeichen ! ``` Ende"
        syntax_tree = self.minilang_parser.parse(teststr)
        assert not syntax_tree.collect_errors()
85
86
87
        delim = str(next(syntax_tree.find(lambda node: node.tag_name == "delimiter")))
        pop = str(next(syntax_tree.find(lambda node: node.tag_name == "Pop")))
        assert delim == pop
88
89
        if WRITE_LOGS:
            syntax_tree.log("test_PopRetrieve_single_line", '.cst')
Eckhart Arnold's avatar
Eckhart Arnold committed
90
            # self.minilang_parser.log_parsing_history("test_PopRetrieve_single_line")
91
92
93
94
95
96
97
98
99
100
101
102

    def test_multi_line(self):
        teststr = """
            Anfang ```code block `` <- keine Ende-Zeichen ! ``` Ebde

            Absatz ohne ``` codeblock, aber
            das stellt sich erst am Ende herause...

            Mehrzeliger ```code block
            """
        syntax_tree = self.minilang_parser.parse(teststr)
        assert not syntax_tree.collect_errors()
103
104
105
        delim = str(next(syntax_tree.find(lambda node: node.tag_name == "delimiter")))
        pop = str(next(syntax_tree.find(lambda node: node.tag_name == "Pop")))
        assert delim == pop
106
107
        if WRITE_LOGS:
            syntax_tree.log("test_PopRetrieve_multi_line", '.cst')
Eckhart Arnold's avatar
Eckhart Arnold committed
108
            # self.minilang_parser.log_parsing_history("test_PopRetrieve_multi_line")
109
110


111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
class TestSemanticValidation:
    def check(self, minilang, bool_filter=lambda x: x):
        grammar = EBNFGrammar()
        st = grammar.parse(minilang)
        assert not st.collect_errors()
        for table in EBNF_ASTPipeline:
            traverse(st, table)
        assert bool_filter(st.collect_errors())

    def test_illegal_nesting(self):
        self.check('impossible = { [ "an optional requirement" ] }')

    def test_illegal_nesting_option_required(self):
        self.check('impossible = [ §"an optional requirement" ]')

    def test_illegal_nesting_oneormore_option(self):
        self.check('impossible = { [ "no use"] }+')

    def test_legal_nesting(self):
        self.check('possible = { [ "+" ] "1" }', lambda x: not x)


class TestCompilerErrors:
    def test_error_propagation(self):
        ebnf = "@ literalws = wrongvalue  # testing error propagation"
        result, messages, st = full_compilation(ebnf, EBNFGrammar(), EBNF_ASTPipeline,
                                                EBNFCompiler('ErrorPropagationTest'))
        assert messages


141
142
if __name__ == "__main__":
    from run import run_tests
143
144

    run_tests("TestCompilerErrors", globals())