1 module dud.sdlang.parser; 2 3 import std.typecons : RefCounted, refCounted; 4 import std.format : format; 5 import dud.sdlang.ast; 6 import dud.sdlang.tokenmodule; 7 8 import dud.sdlang.lexer; 9 10 import dud.sdlang.exception; 11 12 struct Parser { 13 @safe pure: 14 15 import std.array : appender; 16 17 import std.format : formattedWrite; 18 19 Lexer lex; 20 21 this(Lexer lex) { 22 this.lex = lex; 23 } 24 25 bool firstRoot() const pure @nogc @safe { 26 return this.firstTags() 27 || this.firstTagTerminator() 28 || this.lex.front.type == TokenType.eof; 29 } 30 31 Root parseRoot() { 32 try { 33 return this.parseRootImpl(); 34 } catch(ParseException e) { 35 throw new ParseException( 36 "While parsing a Root an Exception was thrown.", 37 e, __FILE__, __LINE__ 38 ); 39 } 40 } 41 42 Root parseRootImpl() { 43 string[] subRules; 44 subRules = ["T"]; 45 if(this.firstTags()) { 46 Tags tags = this.parseTags(); 47 subRules = ["T"]; 48 if(this.lex.front.type == TokenType.eof) { 49 this.lex.popFront(); 50 51 return new Root(RootEnum.T 52 , tags 53 ); 54 } 55 auto app = appender!string(); 56 formattedWrite(app, 57 "In 'Root' found a '%s' while looking for", 58 this.lex.front 59 ); 60 throw new ParseException(app.data, 61 __FILE__, __LINE__, 62 subRules, 63 ["eof"] 64 ); 65 66 } else if(this.firstTagTerminator()) { 67 this.parseTagTerminator(); 68 subRules = ["TT"]; 69 if(this.firstTags()) { 70 Tags tags = this.parseTags(); 71 subRules = ["TT"]; 72 if(this.lex.front.type == TokenType.eof) { 73 this.lex.popFront(); 74 75 return new Root(RootEnum.TT 76 , tags 77 ); 78 } 79 auto app = appender!string(); 80 formattedWrite(app, 81 "In 'Root' found a '%s' while looking for", 82 this.lex.front 83 ); 84 throw new ParseException(app.data, 85 __FILE__, __LINE__, 86 subRules, 87 ["eof"] 88 ); 89 90 } 91 auto app = appender!string(); 92 formattedWrite(app, 93 "In 'Root' found a '%s' while looking for", 94 this.lex.front 95 ); 96 throw new ParseException(app.data, 97 __FILE__, __LINE__, 98 subRules, 99 ["ident -> Tag","lcurly -> Tag","value -> Tag"] 100 ); 101 102 } else if(this.lex.front.type == TokenType.eof) { 103 this.lex.popFront(); 104 105 return new Root(RootEnum.E 106 ); 107 } 108 auto app = appender!string(); 109 formattedWrite(app, 110 "In 'Root' found a '%s' while looking for", 111 this.lex.front 112 ); 113 throw new ParseException(app.data, 114 __FILE__, __LINE__, 115 subRules, 116 ["ident -> Tag","lcurly -> Tag","value -> Tag","eol","semicolon","eof"] 117 ); 118 119 } 120 121 bool firstTags() const pure @nogc @safe { 122 return this.firstTag(); 123 } 124 125 Tags parseTags() { 126 try { 127 return this.parseTagsImpl(); 128 } catch(ParseException e) { 129 throw new ParseException( 130 "While parsing a Tags an Exception was thrown.", 131 e, __FILE__, __LINE__ 132 ); 133 } 134 } 135 136 Tags parseTagsImpl() { 137 string[] subRules; 138 subRules = ["Tag", "TagFollow"]; 139 if(this.firstTag()) { 140 Tag cur = this.parseTag(); 141 subRules = ["TagFollow"]; 142 if(this.firstTags()) { 143 Tags follow = this.parseTags(); 144 145 return new Tags(TagsEnum.TagFollow 146 , cur 147 , follow 148 ); 149 } 150 return new Tags(TagsEnum.Tag 151 , cur 152 ); 153 } 154 auto app = appender!string(); 155 formattedWrite(app, 156 "In 'Tags' found a '%s' while looking for", 157 this.lex.front 158 ); 159 throw new ParseException(app.data, 160 __FILE__, __LINE__, 161 subRules, 162 ["ident -> IDFull","lcurly -> OptChild","value -> Values"] 163 ); 164 165 } 166 167 bool firstTag() const pure @nogc @safe { 168 return this.firstIDFull() 169 || this.firstValues() 170 || this.firstOptChild(); 171 } 172 173 Tag parseTag() { 174 try { 175 return this.parseTagImpl(); 176 } catch(ParseException e) { 177 throw new ParseException( 178 "While parsing a Tag an Exception was thrown.", 179 e, __FILE__, __LINE__ 180 ); 181 } 182 } 183 184 Tag parseTagImpl() { 185 string[] subRules; 186 subRules = ["IA", "IAO", "IAOT", "IAT", "IE", "IET", "IO", "IOT", "IV", "IVA", "IVAO", "IVAOT", "IVAT", "IVO", "IVOT", "IVT"]; 187 if(this.firstIDFull()) { 188 IDFull id = this.parseIDFull(); 189 subRules = ["IV", "IVA", "IVAO", "IVAOT", "IVAT", "IVO", "IVOT", "IVT"]; 190 if(this.firstValues()) { 191 Values vals = this.parseValues(); 192 subRules = ["IVA", "IVAO", "IVAOT", "IVAT"]; 193 if(this.firstAttributes()) { 194 Attributes attrs = this.parseAttributes(); 195 subRules = ["IVAO", "IVAOT"]; 196 if(this.firstOptChild()) { 197 OptChild oc = this.parseOptChild(); 198 subRules = ["IVAOT"]; 199 if(this.firstTagTerminator()) { 200 this.parseTagTerminator(); 201 202 return new Tag(TagEnum.IVAOT 203 , id 204 , vals 205 , attrs 206 , oc 207 ); 208 } 209 return new Tag(TagEnum.IVAO 210 , id 211 , vals 212 , attrs 213 , oc 214 ); 215 } else if(this.firstTagTerminator()) { 216 this.parseTagTerminator(); 217 218 return new Tag(TagEnum.IVAT 219 , id 220 , vals 221 , attrs 222 ); 223 } 224 return new Tag(TagEnum.IVA 225 , id 226 , vals 227 , attrs 228 ); 229 } else if(this.firstOptChild()) { 230 OptChild oc = this.parseOptChild(); 231 subRules = ["IVOT"]; 232 if(this.firstTagTerminator()) { 233 this.parseTagTerminator(); 234 235 return new Tag(TagEnum.IVOT 236 , id 237 , vals 238 , oc 239 ); 240 } 241 return new Tag(TagEnum.IVO 242 , id 243 , vals 244 , oc 245 ); 246 } else if(this.firstTagTerminator()) { 247 this.parseTagTerminator(); 248 249 return new Tag(TagEnum.IVT 250 , id 251 , vals 252 ); 253 } 254 return new Tag(TagEnum.IV 255 , id 256 , vals 257 ); 258 } else if(this.firstAttributes()) { 259 Attributes attrs = this.parseAttributes(); 260 subRules = ["IAO", "IAOT"]; 261 if(this.firstOptChild()) { 262 OptChild oc = this.parseOptChild(); 263 subRules = ["IAOT"]; 264 if(this.firstTagTerminator()) { 265 this.parseTagTerminator(); 266 267 return new Tag(TagEnum.IAOT 268 , id 269 , attrs 270 , oc 271 ); 272 } 273 return new Tag(TagEnum.IAO 274 , id 275 , attrs 276 , oc 277 ); 278 } else if(this.firstTagTerminator()) { 279 this.parseTagTerminator(); 280 281 return new Tag(TagEnum.IAT 282 , id 283 , attrs 284 ); 285 } 286 return new Tag(TagEnum.IA 287 , id 288 , attrs 289 ); 290 } else if(this.firstOptChild()) { 291 OptChild oc = this.parseOptChild(); 292 subRules = ["IOT"]; 293 if(this.firstTagTerminator()) { 294 this.parseTagTerminator(); 295 296 return new Tag(TagEnum.IOT 297 , id 298 , oc 299 ); 300 } 301 return new Tag(TagEnum.IO 302 , id 303 , oc 304 ); 305 } else if(this.firstTagTerminator()) { 306 this.parseTagTerminator(); 307 308 return new Tag(TagEnum.IET 309 , id 310 ); 311 } 312 return new Tag(TagEnum.IE 313 , id 314 ); 315 } else if(this.firstValues()) { 316 Values vals = this.parseValues(); 317 subRules = ["VA", "VAO", "VAOT", "VAT"]; 318 if(this.firstAttributes()) { 319 Attributes attrs = this.parseAttributes(); 320 subRules = ["VAO", "VAOT"]; 321 if(this.firstOptChild()) { 322 OptChild oc = this.parseOptChild(); 323 subRules = ["VAOT"]; 324 if(this.firstTagTerminator()) { 325 this.parseTagTerminator(); 326 327 return new Tag(TagEnum.VAOT 328 , vals 329 , attrs 330 , oc 331 ); 332 } 333 return new Tag(TagEnum.VAO 334 , vals 335 , attrs 336 , oc 337 ); 338 } else if(this.firstTagTerminator()) { 339 this.parseTagTerminator(); 340 341 return new Tag(TagEnum.VAT 342 , vals 343 , attrs 344 ); 345 } 346 return new Tag(TagEnum.VA 347 , vals 348 , attrs 349 ); 350 } else if(this.firstOptChild()) { 351 OptChild oc = this.parseOptChild(); 352 subRules = ["VOT"]; 353 if(this.firstTagTerminator()) { 354 this.parseTagTerminator(); 355 356 return new Tag(TagEnum.VOT 357 , vals 358 , oc 359 ); 360 } 361 return new Tag(TagEnum.VO 362 , vals 363 , oc 364 ); 365 } else if(this.firstTagTerminator()) { 366 this.parseTagTerminator(); 367 368 return new Tag(TagEnum.VT 369 , vals 370 ); 371 } 372 return new Tag(TagEnum.V 373 , vals 374 ); 375 } else if(this.firstOptChild()) { 376 OptChild oc = this.parseOptChild(); 377 subRules = ["OT"]; 378 if(this.firstTagTerminator()) { 379 this.parseTagTerminator(); 380 381 return new Tag(TagEnum.OT 382 , oc 383 ); 384 } 385 return new Tag(TagEnum.O 386 , oc 387 ); 388 } 389 auto app = appender!string(); 390 formattedWrite(app, 391 "In 'Tag' found a '%s' while looking for", 392 this.lex.front 393 ); 394 throw new ParseException(app.data, 395 __FILE__, __LINE__, 396 subRules, 397 ["ident","value","lcurly"] 398 ); 399 400 } 401 402 bool firstIDFull() const pure @nogc @safe { 403 return this.lex.front.type == TokenType.ident; 404 } 405 406 IDFull parseIDFull() { 407 try { 408 return this.parseIDFullImpl(); 409 } catch(ParseException e) { 410 throw new ParseException( 411 "While parsing a IDFull an Exception was thrown.", 412 e, __FILE__, __LINE__ 413 ); 414 } 415 } 416 417 IDFull parseIDFullImpl() { 418 string[] subRules; 419 subRules = ["L", "S"]; 420 if(this.lex.front.type == TokenType.ident) { 421 Token cur = this.lex.front; 422 this.lex.popFront(); 423 subRules = ["L"]; 424 if(this.lex.front.type == TokenType.colon) { 425 this.lex.popFront(); 426 subRules = ["L"]; 427 if(this.firstIDFull()) { 428 IDFull follow = this.parseIDFull(); 429 430 return new IDFull(IDFullEnum.L 431 , cur 432 , follow 433 ); 434 } 435 auto app = appender!string(); 436 formattedWrite(app, 437 "In 'IDFull' found a '%s' while looking for", 438 this.lex.front 439 ); 440 throw new ParseException(app.data, 441 __FILE__, __LINE__, 442 subRules, 443 ["ident"] 444 ); 445 446 } 447 return new IDFull(IDFullEnum.S 448 , cur 449 ); 450 } 451 auto app = appender!string(); 452 formattedWrite(app, 453 "In 'IDFull' found a '%s' while looking for", 454 this.lex.front 455 ); 456 throw new ParseException(app.data, 457 __FILE__, __LINE__, 458 subRules, 459 ["ident"] 460 ); 461 462 } 463 464 bool firstValues() const pure @nogc @safe { 465 return this.lex.front.type == TokenType.value; 466 } 467 468 Values parseValues() { 469 try { 470 return this.parseValuesImpl(); 471 } catch(ParseException e) { 472 throw new ParseException( 473 "While parsing a Values an Exception was thrown.", 474 e, __FILE__, __LINE__ 475 ); 476 } 477 } 478 479 Values parseValuesImpl() { 480 string[] subRules; 481 subRules = ["Value", "ValueFollow"]; 482 if(this.lex.front.type == TokenType.value) { 483 Token cur = this.lex.front; 484 this.lex.popFront(); 485 subRules = ["ValueFollow"]; 486 if(this.firstValues()) { 487 Values follow = this.parseValues(); 488 489 return new Values(ValuesEnum.ValueFollow 490 , cur 491 , follow 492 ); 493 } 494 return new Values(ValuesEnum.Value 495 , cur 496 ); 497 } 498 auto app = appender!string(); 499 formattedWrite(app, 500 "In 'Values' found a '%s' while looking for", 501 this.lex.front 502 ); 503 throw new ParseException(app.data, 504 __FILE__, __LINE__, 505 subRules, 506 ["value"] 507 ); 508 509 } 510 511 bool firstAttributes() const pure @nogc @safe { 512 return this.firstAttribute(); 513 } 514 515 Attributes parseAttributes() { 516 try { 517 return this.parseAttributesImpl(); 518 } catch(ParseException e) { 519 throw new ParseException( 520 "While parsing a Attributes an Exception was thrown.", 521 e, __FILE__, __LINE__ 522 ); 523 } 524 } 525 526 Attributes parseAttributesImpl() { 527 string[] subRules; 528 subRules = ["Attribute", "AttributeFollow"]; 529 if(this.firstAttribute()) { 530 Attribute cur = this.parseAttribute(); 531 subRules = ["AttributeFollow"]; 532 if(this.firstAttributes()) { 533 Attributes follow = this.parseAttributes(); 534 535 return new Attributes(AttributesEnum.AttributeFollow 536 , cur 537 , follow 538 ); 539 } 540 return new Attributes(AttributesEnum.Attribute 541 , cur 542 ); 543 } 544 auto app = appender!string(); 545 formattedWrite(app, 546 "In 'Attributes' found a '%s' while looking for", 547 this.lex.front 548 ); 549 throw new ParseException(app.data, 550 __FILE__, __LINE__, 551 subRules, 552 ["ident -> IDFull"] 553 ); 554 555 } 556 557 bool firstAttribute() const pure @nogc @safe { 558 return this.firstIDFull(); 559 } 560 561 Attribute parseAttribute() { 562 try { 563 return this.parseAttributeImpl(); 564 } catch(ParseException e) { 565 throw new ParseException( 566 "While parsing a Attribute an Exception was thrown.", 567 e, __FILE__, __LINE__ 568 ); 569 } 570 } 571 572 Attribute parseAttributeImpl() { 573 string[] subRules; 574 subRules = ["A"]; 575 if(this.firstIDFull()) { 576 IDFull id = this.parseIDFull(); 577 subRules = ["A"]; 578 if(this.lex.front.type == TokenType.assign) { 579 this.lex.popFront(); 580 subRules = ["A"]; 581 if(this.lex.front.type == TokenType.value) { 582 Token value = this.lex.front; 583 this.lex.popFront(); 584 585 return new Attribute(AttributeEnum.A 586 , id 587 , value 588 ); 589 } 590 auto app = appender!string(); 591 formattedWrite(app, 592 "In 'Attribute' found a '%s' while looking for", 593 this.lex.front 594 ); 595 throw new ParseException(app.data, 596 __FILE__, __LINE__, 597 subRules, 598 ["value"] 599 ); 600 601 } 602 auto app = appender!string(); 603 formattedWrite(app, 604 "In 'Attribute' found a '%s' while looking for", 605 this.lex.front 606 ); 607 throw new ParseException(app.data, 608 __FILE__, __LINE__, 609 subRules, 610 ["assign"] 611 ); 612 613 } 614 auto app = appender!string(); 615 formattedWrite(app, 616 "In 'Attribute' found a '%s' while looking for", 617 this.lex.front 618 ); 619 throw new ParseException(app.data, 620 __FILE__, __LINE__, 621 subRules, 622 ["ident"] 623 ); 624 625 } 626 627 bool firstOptChild() const pure @nogc @safe { 628 return this.lex.front.type == TokenType.lcurly; 629 } 630 631 OptChild parseOptChild() { 632 try { 633 return this.parseOptChildImpl(); 634 } catch(ParseException e) { 635 throw new ParseException( 636 "While parsing a OptChild an Exception was thrown.", 637 e, __FILE__, __LINE__ 638 ); 639 } 640 } 641 642 OptChild parseOptChildImpl() { 643 string[] subRules; 644 subRules = ["E", "E2", "T"]; 645 if(this.lex.front.type == TokenType.lcurly) { 646 this.lex.popFront(); 647 subRules = ["E", "T"]; 648 if(this.firstTagTerminator()) { 649 this.parseTagTerminator(); 650 subRules = ["T"]; 651 if(this.firstTags()) { 652 Tags tags = this.parseTags(); 653 subRules = ["T"]; 654 if(this.lex.front.type == TokenType.rcurly) { 655 this.lex.popFront(); 656 657 return new OptChild(OptChildEnum.T 658 , tags 659 ); 660 } 661 auto app = appender!string(); 662 formattedWrite(app, 663 "In 'OptChild' found a '%s' while looking for", 664 this.lex.front 665 ); 666 throw new ParseException(app.data, 667 __FILE__, __LINE__, 668 subRules, 669 ["rcurly"] 670 ); 671 672 } else if(this.lex.front.type == TokenType.rcurly) { 673 this.lex.popFront(); 674 675 return new OptChild(OptChildEnum.E 676 ); 677 } 678 auto app = appender!string(); 679 formattedWrite(app, 680 "In 'OptChild' found a '%s' while looking for", 681 this.lex.front 682 ); 683 throw new ParseException(app.data, 684 __FILE__, __LINE__, 685 subRules, 686 ["ident -> Tag","lcurly -> Tag","value -> Tag","rcurly"] 687 ); 688 689 } else if(this.lex.front.type == TokenType.rcurly) { 690 this.lex.popFront(); 691 692 return new OptChild(OptChildEnum.E2 693 ); 694 } 695 auto app = appender!string(); 696 formattedWrite(app, 697 "In 'OptChild' found a '%s' while looking for", 698 this.lex.front 699 ); 700 throw new ParseException(app.data, 701 __FILE__, __LINE__, 702 subRules, 703 ["eol","semicolon","rcurly"] 704 ); 705 706 } 707 auto app = appender!string(); 708 formattedWrite(app, 709 "In 'OptChild' found a '%s' while looking for", 710 this.lex.front 711 ); 712 throw new ParseException(app.data, 713 __FILE__, __LINE__, 714 subRules, 715 ["lcurly"] 716 ); 717 718 } 719 720 bool firstTagTerminator() const pure @nogc @safe { 721 return this.lex.front.type == TokenType.eol 722 || this.lex.front.type == TokenType.semicolon; 723 } 724 725 TagTerminator parseTagTerminator() { 726 try { 727 return this.parseTagTerminatorImpl(); 728 } catch(ParseException e) { 729 throw new ParseException( 730 "While parsing a TagTerminator an Exception was thrown.", 731 e, __FILE__, __LINE__ 732 ); 733 } 734 } 735 736 TagTerminator parseTagTerminatorImpl() { 737 string[] subRules; 738 subRules = ["E", "EF"]; 739 if(this.lex.front.type == TokenType.eol) { 740 this.lex.popFront(); 741 subRules = ["EF"]; 742 if(this.firstTagTerminator()) { 743 this.parseTagTerminator(); 744 745 return new TagTerminator(TagTerminatorEnum.EF 746 ); 747 } 748 return new TagTerminator(TagTerminatorEnum.E 749 ); 750 } else if(this.lex.front.type == TokenType.semicolon) { 751 this.lex.popFront(); 752 subRules = ["SF"]; 753 if(this.firstTagTerminator()) { 754 this.parseTagTerminator(); 755 756 return new TagTerminator(TagTerminatorEnum.SF 757 ); 758 } 759 return new TagTerminator(TagTerminatorEnum.S 760 ); 761 } 762 auto app = appender!string(); 763 formattedWrite(app, 764 "In 'TagTerminator' found a '%s' while looking for", 765 this.lex.front 766 ); 767 throw new ParseException(app.data, 768 __FILE__, __LINE__, 769 subRules, 770 ["eol","semicolon"] 771 ); 772 773 } 774 775 }