test_ebnf.py 5.84 KB
Newer Older
1
2
#!/usr/bin/python3

3
"""test_ebnf.py - tests of the EBNFcompiler-module of DHParser 
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
                             

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
from DHParser.syntaxtree import traverse
27
28
29
from DHParser.parsers import full_compilation
from DHParser.ebnf import EBNFGrammar, EBNF_ASTPipeline, EBNFCompiler
from DHParser.dsl 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")
50
        # parser.log_parsing_history("WSP")
51
52
        assert not syntax_tree.collect_errors()
        syntax_tree = parser.parse("3 + 4 \n * 12")
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
        # parser.log_parsing_history("WSPLF")
        assert not syntax_tree.collect_errors()
        syntax_tree = parser.parse("3 + 4 \n \n * 12")
        assert syntax_tree.collect_errors()
        syntax_tree = parser.parse("3 + 4 \n\n * 12")
        assert syntax_tree.collect_errors()

    def test_whitespace_vertical(self):
        lang = "@ whitespace = vertical\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 not syntax_tree.collect_errors()
        syntax_tree = parser.parse("3 + 4 \n \n * 12")
        assert not syntax_tree.collect_errors()
        syntax_tree = parser.parse("3 + 4 \n\n * 12")
71
72
        assert not syntax_tree.collect_errors()

73
74
    def test_whitespace_horizontal(self):
        lang = "@ whitespace = horizontal\n" + self.mini_language
75
76
77
78
79
80
81
        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()

82

83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
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()
102
103
104
        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
105
106
        if WRITE_LOGS:
            syntax_tree.log("test_PopRetrieve_single_line", '.cst')
Eckhart Arnold's avatar
Eckhart Arnold committed
107
            # self.minilang_parser.log_parsing_history("test_PopRetrieve_single_line")
108
109
110
111
112
113
114
115
116
117
118
119

    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()
120
121
122
        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
123
124
        if WRITE_LOGS:
            syntax_tree.log("test_PopRetrieve_multi_line", '.cst')
Eckhart Arnold's avatar
Eckhart Arnold committed
125
            # self.minilang_parser.log_parsing_history("test_PopRetrieve_multi_line")
126
127


128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
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):
152
153
        ebnf = "@ literalws = wrongvalue  # testing error propagation\n"
        result, messages, st = full_compilation(ebnf, None, EBNFGrammar(), EBNF_ASTPipeline,
154
155
156
157
                                                EBNFCompiler('ErrorPropagationTest'))
        assert messages


158
159
if __name__ == "__main__":
    from run import run_tests
160

161
    run_tests("TestDirectives", globals())