1 module generatortests;
2 import dparsergen.generator.ebnf;
3 import dparsergen.generator.generator;
4 import dparsergen.generator.grammar;
5 import dparsergen.generator.production;
6 import std.algorithm;
7 import std.array;
8 import std.conv;
9 
10 bool equalWithoutWhite(string a, string b)
11 {
12     while (true)
13     {
14         while (!a.empty && (a.front == ' ' || a.front == '\t' || a.front == '\r'))
15             a.popFront;
16         while (!b.empty && (b.front == ' ' || b.front == '\t' || b.front == '\r'))
17             b.popFront;
18         if (a.empty && b.empty)
19             return true;
20         if (a.empty || b.empty)
21             return false;
22         if (a.front != b.front)
23             return false;
24         a.popFront;
25         b.popFront;
26     }
27 }
28 
29 struct FirstSetTest
30 {
31     string name;
32     string[] firstSet;
33 }
34 
35 unittest
36 {
37     EBNFGrammar test(string gr, string expected, FirstSetTest[] firstSets = [],
38             string filename = __FILE__, size_t line = __LINE__)
39     {
40         EBNFGrammar grammar = gr.parseEBNF2("").createGrammar();
41         string grammartext = text(grammar);
42         assert(equalWithoutWhite(grammartext, expected), text(filename, ":", line,
43                 "\n", "got: \"", grammartext, "\"\nexpected: \"", expected, "\""));
44         foreach (t; firstSets)
45         {
46             SymbolInstance[] s = [SymbolInstance(grammar.nonterminals.getID(t.name))];
47             auto f = grammar.firstSet(s);
48             string[] f2;
49             foreach (x; f.bitsSet)
50             {
51                 f2 ~= grammar.getSymbolName(x);
52             }
53             assert(f2 == t.firstSet, text(t.name, " ", f2, " ", t.firstSet));
54         }
55 
56         return grammar;
57     }
58 
59     test(q{S = "x"| "y" S;},
60     q{EBNFGrammar
61         S = "x"
62         S = "y" S
63     });
64 
65     test(q{S = X?; X = "x";},
66     q{EBNFGrammar
67         X? = <X [virtual]
68         X? = [virtual]
69         S = X?
70         X = "x"
71     });
72 
73     test(q{S = id("a");id(b) = b;},
74     q{EBNFGrammar
75         id("a") = "a"
76         S = id("a")
77     });
78 
79     test(q{S = list(X);list(b) = b|list(b) b;X = "x";},
80     q{EBNFGrammar
81         list(X) = X
82         list(X) = list(X) X
83         S = list(X)
84         X = "x"
85     });
86 
87     test(q{S = list(X,",");list(e,s) = e|list(e,s) s e;X = "x";},
88     q{EBNFGrammar
89         list(X, ",") = X
90         list(X, ",") = list(X, ",") "," X
91         S = list(X, ",")
92         X = "x"
93     });
94 
95     test(q{S = list(X,",");list(e,s) = e|list(e,s) ^s e;X = "x";},
96     q{EBNFGrammar
97         list(X, ",") = X
98         list(X, ",") = list(X, ",") ^"," X
99         S = list(X, ",")
100         X = "x"
101     });
102 
103     test(q{S @a = @b "x" @c "y" @d;},
104     q{EBNFGrammar
105         S @a = @b "x" @c "y" @d
106     });
107 
108     test(q{S = "s" | "if" "(" S ")" S | "if" "(" S ")" S "else" S;},
109     q{EBNFGrammar
110         S = "s"
111         S = "if" "(" S ")" S
112         S = "if" "(" S ")" S "else" S
113     });
114 
115     test(q{S = "s" | "if" "(" S ")" S !"else" | "if" "(" S ")" S "else" S;},
116     q{EBNFGrammar
117         S = "s"
118         S = "if" "(" S ")" S !"else"
119         S = "if" "(" S ")" S "else" S
120     });
121 
122     test(q{S = A? B?;A = "@" "a";B = "@" "b";},
123     q{EBNFGrammar
124         A? = <A [virtual]
125         A? = [virtual]
126         B? = <B [virtual]
127         B? = [virtual]
128         S = A? B?
129         A = "@" "a"
130         B = "@" "b"
131     });
132 
133     test(q{
134         Module = star("A") | star("B");
135         star(e) = @empty | star(e) e;
136     },
137     q{EBNFGrammar
138         star("A") = @empty
139         star("A") = star("A") "A"
140         Module = star("A")
141         star("B") = @empty
142         star("B") = star("B") "B"
143         Module = star("B")
144     });
145 
146     test(q{
147         Module = repeat("A" "B");
148         star(e) = @empty | star(e) e;
149         repeat(e) = e star(e);
150     },
151     q{EBNFGrammar
152         {"A"_"B"} = "A" "B"
153         star({"A" "B"}) = @empty
154         star({"A" "B"}) = star({"A" "B"}) {"A"_"B"}
155         repeat({"A" "B"}) = {"A"_"B"} star({"A" "B"})
156         Module = repeat({"A" "B"})
157     });
158 
159     test(q{
160         Module = repeat("A"|"B");
161         star(e) = @empty | star(e) e;
162         repeat(e) = e star(e);
163     },
164     q{EBNFGrammar
165         {"A"_|_"B"} = "A"
166         {"A"_|_"B"} = "B"
167         star({"A" | "B"}) = @empty
168         star({"A" | "B"}) = star({"A" | "B"}) {"A"_|_"B"}
169         repeat({"A" | "B"}) = {"A"_|_"B"} star({"A" | "B"})
170         Module = repeat({"A" | "B"})
171     });
172 
173     test(q{
174         PostfixExp = PrimaryExpression
175                    star( FieldAccessExp
176                    | TemplateFuncExp );
177 
178         FieldAccessExp = "_" "id";
179 
180         TemplateFuncExp = "!" "id";
181         star(e) @array = @empty | star(e) e;
182         PrimaryExpression = "primary";
183     },
184     q{EBNFGrammar
185           star({FieldAccessExp | TemplateFuncExp}) @array = @empty
186           {FieldAccessExp_|_TemplateFuncExp} = FieldAccessExp
187           {FieldAccessExp_|_TemplateFuncExp} = TemplateFuncExp
188           star({FieldAccessExp | TemplateFuncExp}) @array = star({FieldAccessExp | TemplateFuncExp}) {FieldAccessExp_|_TemplateFuncExp}
189           PostfixExp = PrimaryExpression star({FieldAccessExp | TemplateFuncExp})
190           FieldAccessExp = "_" "id"
191           TemplateFuncExp = "!" "id"
192           PrimaryExpression = "primary"
193     },[
194         FirstSetTest("TemplateFuncExp",["\"!\""]),
195         FirstSetTest("{FieldAccessExp_|_TemplateFuncExp}",["\"_\"","\"!\""]),
196         FirstSetTest("PostfixExp",["\"primary\""]),
197         FirstSetTest("star({FieldAccessExp | TemplateFuncExp})",["$end","\"_\"","\"!\""]),
198     ]);
199 
200     auto grammarTags1 = test(q{
201         S = A | B;
202         A = @rejectTag(T1) Y;
203         B = @needTag(T1) Y;
204         Y = @inheritTag(T1) @inheritTag(T2) @inheritTag(T3) X;
205         X = "x1" @tag(T1)
206           | "x2" @tag(T2)
207           | "x3" @tag(T3);
208     },
209     q{EBNFGrammar
210           S = A
211           S = B
212           A = @rejectTag(T1) Y
213           B = @needTag(T1) Y
214           Y = @inheritTag(T1) @inheritTag(T2) @inheritTag(T3) X
215           X = "x1" @tag(T1)
216           X = "x2" @tag(T2)
217           X = "x3" @tag(T3)
218     }, [
219         FirstSetTest("X", ["\"x1\"", "\"x2\"", "\"x3\""]),
220         FirstSetTest("Y", ["\"x1\"", "\"x2\"", "\"x3\""]),
221         FirstSetTest("A", ["\"x2\"", "\"x3\""]),
222         // TODO FirstSetTest("B", ["\"x1\""]),
223         FirstSetTest("S", ["\"x1\"", "\"x2\"", "\"x3\""]),
224     ]);
225 
226     static string tagsString(EBNFGrammar grammar, immutable(TagID)[] tags)
227     {
228         string[] strings;
229         foreach (tag; tags)
230         {
231             strings ~= grammar.tags[tag].name;
232         }
233         strings.sort();
234         return strings.join(" ");
235     }
236 
237     assert(tagsString(grammarTags1, grammarTags1.nonterminals.get("S").possibleTags) == "");
238     assert(tagsString(grammarTags1, grammarTags1.nonterminals.get("A").possibleTags) == "");
239     assert(tagsString(grammarTags1, grammarTags1.nonterminals.get("B").possibleTags) == "");
240     assert(tagsString(grammarTags1, grammarTags1.nonterminals.get("Y").possibleTags) == "T1 T2 T3");
241     assert(tagsString(grammarTags1, grammarTags1.nonterminals.get("X").possibleTags) == "T1 T2 T3");
242 
243     test(q{
244         EOF = !anytoken @empty;
245     },
246     q{EBNFGrammar
247         EOF = !anytoken @empty
248     });
249     test(q{
250         S = Identifier | Test;
251         token Identifier = [a - zA - Z_] [a - zA - Z0 - 9]*;
252         Test = Identifier>>"test";
253     },
254     q{EBNFGrammar
255         S = Identifier
256         S = Test
257         Test = Identifier>>"test"
258     });
259 
260     test(q{
261         Module = or("A","B");
262         or(e) = e;
263         or(e1, e2, r...) = e1 | or(e2, r...);
264     },
265     q{EBNFGrammar
266        or("A", "B") = "A"
267        or("B") = "B"
268        or("A", "B") = or("B")
269        Module = or("A", "B")
270     });
271 
272     test(q{
273         Module = or("A","B");
274         or(e) = e;
275         or(r..., e1, e2) = e1 | or(r..., e2);
276     },
277     q{EBNFGrammar
278        or("A", "B") = "A"
279        or("B") = "B"
280        or("A", "B") = or("B")
281        Module = or("A", "B")
282     });
283 
284     test(q{
285         Module = or("A","B");
286         or(e) = e;
287         or(e1, r..., e2) = e1 | or(r..., e2);
288     },
289     q{EBNFGrammar
290        or("A", "B") = "A"
291        or("B") = "B"
292        or("A", "B") = or("B")
293        Module = or("A", "B")
294     });
295 
296     test(q{
297         Module = or("A","B","C","D");
298         or(e) = e;
299         or(e1, e2, r...) = e1 | or(e2, r...);
300     },
301     q{EBNFGrammar
302        or("A", "B", "C", "D") = "A"
303        or("B", "C", "D") = "B"
304        or("C", "D") = "C"
305        or("D") = "D"
306        or("C", "D") = or("D")
307        or("B", "C", "D") = or("C", "D")
308        or("A", "B", "C", "D") = or("B", "C", "D")
309        Module = or("A", "B", "C", "D")
310     });
311 
312     test(q{
313         Module = test(t("A","B"), t("C","D"));
314         test(a, b) = or(a...) or(b...);
315         or(e) = e;
316         or(e1, e2, r...) = e1 | or(e2, r...);
317     },
318     q{EBNFGrammar
319        or("A", "B") = "A"
320        or("B") = "B"
321        or("A", "B") = or("B")
322        or("C", "D") = "C"
323        or("D") = "D"
324        or("C", "D") = or("D")
325        test(t("A", "B"), t("C", "D")) = or("A", "B") or("C", "D")
326        Module = test(t("A", "B"), t("C", "D"))
327     });
328 
329     test(q{
330         Module = listof("A","B");
331         listof() = @empty;
332         listof(e, r...) = listof(e, r...) or(e, r...) | listof2(t(), e, r...);
333         listof2(done, e) = listof(done...) e;
334         listof2(done, e, e2, r...) = listof(done..., e2, r...) e | listof2(t(done..., e), e2, r...);
335         or(e) = e;
336         or(e1, e2, r...) = e1 | or(e2, r...);
337     },
338     q{EBNFGrammar
339         or("A", "B") = "A"
340         or("B") = "B"
341         or("A", "B") = or("B")
342         listof("A", "B") = listof("A", "B") or("A", "B")
343         listof("B") = listof("B") or("B")
344         listof() = @empty
345         listof2(t(), "B") = listof() "B"
346         listof("B") = listof2(t(), "B")
347         listof2(t(), "A", "B") = listof("B") "A"
348         or("A") = "A"
349         listof("A") = listof("A") or("A")
350         listof2(t(), "A") = listof() "A"
351         listof("A") = listof2(t(), "A")
352         listof2(t("A"), "B") = listof("A") "B"
353         listof2(t(), "A", "B") = listof2(t("A"), "B")
354         listof("A", "B") = listof2(t(), "A", "B")
355         Module = listof("A", "B")
356         listof = @empty
357     });
358 
359     test(q{
360         S = As | Bs | Cs | Ds;
361         As = "a"*;
362         Bs = B*;
363         B = "b";
364         Cs = "c" "C"*;
365         Ds = D D*;
366         D = "d";
367     },
368     q{EBNFGrammar
369         S = As
370         S = Bs
371         S = Cs
372         S = Ds
373         "a"+ @array = "a" [virtual]
374         "a"+ @array = "a"+ "a" [virtual]
375         "a"* @array = [virtual]
376         "a"* @array = "a"+ [virtual]
377         As = "a"*
378         B+ @array = B [virtual]
379         B+ @array = B+ B [virtual]
380         B* @array = [virtual]
381         B* @array = B+ [virtual]
382         Bs = B*
383         B = "b"
384         "C"+ @array = "C" [virtual]
385         "C"+ @array = "C"+ "C" [virtual]
386         "C"* @array = [virtual]
387         "C"* @array = "C"+ [virtual]
388         Cs = "c" "C"*
389         D+ @array = D [virtual]
390         D+ @array = D+ D [virtual]
391         D* @array = [virtual]
392         D* @array = D+ [virtual]
393         Ds = D D*
394         D = "d"
395     });
396 
397     test(q{
398         S = As | Bs | Cs | Ds;
399         As = "a"+;
400         Bs = B+;
401         B = "b";
402         Cs = "c" "C"+;
403         Ds = D D+;
404         D = "d";
405     },
406     q{EBNFGrammar
407         S = As
408         S = Bs
409         S = Cs
410         S = Ds
411         "a"+ @array = "a" [virtual]
412         "a"+ @array = "a"+ "a" [virtual]
413         As = "a"+
414         B+ @array = B [virtual]
415         B+ @array = B+ B [virtual]
416         Bs = B+
417         B = "b"
418         "C"+ @array = "C" [virtual]
419         "C"+ @array = "C"+ "C" [virtual]
420         Cs = "c" "C"+
421         D+ @array = D [virtual]
422         D+ @array = D+ D [virtual]
423         Ds = D D+
424         D = "d"
425     });
426 
427     test(q{
428         S = As | Bs;
429         As = "a"?;
430         Bs = B?;
431         B = "b";
432     },
433     q{EBNFGrammar
434         S = As
435         S = Bs
436         "a"? = <"a" [virtual]
437         "a"? = [virtual]
438         As = "a"?
439         B? = <B [virtual]
440         B? = [virtual]
441         Bs = B?
442         B = "b"
443     });
444 }
445 
446 unittest
447 {
448     void test(string gr, string expected)
449     {
450         auto ebnf = gr.parseEBNF2("");
451         EBNFGrammar grammar = ebnf.createGrammar();
452         grammar = createOptEmptyGrammar(ebnf, grammar);
453         string grammartext = text(grammar);
454         assert(equalWithoutWhite(grammartext, expected),
455               text("got: \"", grammartext, "\"\nexpected: \"", expected, "\""));
456     }
457 
458     test(q{
459         S = T;
460         T = A? B? C?;
461         A = "a";
462         B = "b";
463         C = "c";
464     },
465     q{EBNFGrammar
466         A? = <A [virtual]
467         B? = <B [virtual]
468         C? = <C [virtual]
469         A = "a"
470         B = "b"
471         C = "c"
472         S = T
473         T = C?
474         T = B?
475         T = B? C?
476         T = A?
477         T = A? C?
478         T = A? B?
479         T = A? B? C?
480     });
481 
482     test(q{
483         S = T;
484         T = A? B C?;
485         A = "a";
486         B = @empty;
487         C = "c";
488     },
489     q{EBNFGrammar
490         A? = <A [virtual]
491         C? = <C [virtual]
492         A = "a"
493         C = "c"
494         S = T
495         T = C?
496         T = A?
497         T = A? C?
498     });
499 }