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 }