1 module ctpg.dsl.typed.parsers; 2 3 import std.typecons : Tuple; 4 5 import ctpg : parse; 6 7 import ctpg.caller : Caller; 8 import ctpg.input : Input; 9 import ctpg.macro_ : MAKE_RESULT; 10 import ctpg.none : None; 11 import ctpg.option : Option; 12 import ctpg.parse_result : ParseResult; 13 import ctpg.parser_kind : ParserKind; 14 15 import ctpg.dsl.typed.node : Node; 16 import ctpg.dsl.typed.token : Token, TokenType; 17 18 import parsers = ctpg.parsers; 19 import combinators = ctpg.combinators; 20 import ownCombinators = ctpg.dsl.typed.combinators; 21 22 import compile_time_unittest : enableCompileTimeUnittest; 23 mixin enableCompileTimeUnittest; 24 25 26 template identifier() 27 { 28 template build(alias kind, SrcType) 29 { 30 mixin MAKE_RESULT!q{ SrcType }; 31 32 Result parse(Input!SrcType input, in Caller caller) 33 { 34 return combinators.inputSlice! 35 ( 36 combinators.sequence! 37 ( 38 combinators.choice! 39 ( 40 parsers.charRange!('a', 'z'), 41 parsers.charRange!('A', 'Z'), 42 parsers.string_!"_", 43 ), 44 combinators.more0! 45 ( 46 combinators.choice! 47 ( 48 parsers.charRange!('a', 'z'), 49 parsers.charRange!('A', 'Z'), 50 parsers.charRange!('0', '9'), 51 parsers.string_!"_", 52 ) 53 ) 54 ) 55 ).build!(kind, SrcType).parse(input, caller); 56 } 57 } 58 } 59 60 debug(ctpg) unittest 61 { 62 with(parse!identifier("_ab0=")) 63 { 64 assert(match == true); 65 assert(nextInput.source == "="); 66 assert(value == "_ab0"); 67 } 68 } 69 70 71 template doubleQuotedString() 72 { 73 template build(alias kind, SrcType) 74 { 75 mixin MAKE_RESULT!q{ SrcType }; 76 77 static Result parse(Input!SrcType input, in Caller caller) 78 { 79 return combinators.inputSlice! 80 ( 81 combinators.sequence! 82 ( 83 parsers.string_!`"`, 84 combinators.more0! 85 ( 86 combinators.sequence! 87 ( 88 combinators.notPred! 89 ( 90 parsers.string_!`"` 91 ), 92 combinators.choice! 93 ( 94 parsers.string_!`\"`, 95 parsers.anyChar!() 96 ) 97 ) 98 ), 99 parsers.string_!`"` 100 ) 101 ).build!(kind, SrcType).parse(input, caller); 102 } 103 } 104 } 105 106 107 template wysiwygString() 108 { 109 template build(alias kind, SrcType) 110 { 111 mixin MAKE_RESULT!q{ SrcType }; 112 113 static Result parse(Input!SrcType input, in Caller caller) 114 { 115 return combinators.inputSlice! 116 ( 117 combinators.sequence! 118 ( 119 parsers.string_!`r"`, 120 combinators.more0! 121 ( 122 combinators.sequence! 123 ( 124 combinators.notPred! 125 ( 126 parsers.string_!`"` 127 ), 128 parsers.anyChar!() 129 ) 130 ), 131 parsers.string_!`"` 132 ) 133 ).build!(kind, SrcType).parse(input, caller); 134 } 135 } 136 } 137 138 139 template alternateWysiwygString() 140 { 141 template build(alias kind, SrcType) 142 { 143 mixin MAKE_RESULT!q{ SrcType }; 144 145 static Result parse(Input!SrcType input, in Caller caller) 146 { 147 return combinators.inputSlice! 148 ( 149 combinators.sequence! 150 ( 151 parsers.string_!"`", 152 combinators.more0! 153 ( 154 combinators.sequence! 155 ( 156 combinators.notPred! 157 ( 158 parsers.string_!"`" 159 ), 160 parsers.anyChar!() 161 ) 162 ), 163 parsers.string_!"`" 164 ) 165 ).build!(kind, SrcType).parse(input, caller); 166 } 167 } 168 } 169 170 171 template stringLiteral() 172 { 173 template build(alias kind, SrcType) 174 { 175 mixin MAKE_RESULT!q{ SrcType }; 176 177 Result parse(Input!SrcType input, in Caller caller) 178 { 179 return combinators.inputSlice! 180 ( 181 combinators.choice! 182 ( 183 wysiwygString!(), 184 alternateWysiwygString!(), 185 doubleQuotedString!() 186 ) 187 ).build!(kind, SrcType).parse(input, caller); 188 } 189 } 190 } 191 192 debug(ctpg) unittest 193 { 194 with(parse!stringLiteral(`"foo"`)) 195 { 196 assert(match == true); 197 assert(value == `"foo"`); 198 assert(nextInput.source == ""); 199 } 200 201 with(parse!stringLiteral(`"foo\nbar"`)) 202 { 203 assert(match == true); 204 assert(value == `"foo\nbar"`); 205 assert(nextInput.source == ""); 206 } 207 208 with(parse!stringLiteral(`"foo\"bar"`)) 209 { 210 assert(match == true); 211 assert(value == `"foo\"bar"`); 212 assert(nextInput.source == ""); 213 } 214 215 with(parse!stringLiteral(`"foo"bar"`)) 216 { 217 assert(match == true); 218 assert(value == `"foo"`); 219 assert(nextInput.source == `bar"`); 220 } 221 222 with(parse!stringLiteral(`r"foo\"bar"`)) 223 { 224 assert(match == true); 225 assert(value == `r"foo\"`); 226 assert(nextInput.source == `bar"`); 227 } 228 229 with(parse!stringLiteral("`foo`bar`")) 230 { 231 assert(match == true); 232 assert(value == "`foo`"); 233 assert(nextInput.source == "bar`"); 234 } 235 } 236 237 238 // 一行コメントを消費するパーサ 239 template lineComment() 240 { 241 template build(alias kind, SrcType) 242 { 243 mixin MAKE_RESULT!q{ None }; 244 245 Result parse(Input!SrcType input, in Caller caller) 246 { 247 return combinators.none! 248 ( 249 combinators.sequence! 250 ( 251 parsers.string_!"//", 252 combinators.more0! 253 ( 254 combinators.sequence! 255 ( 256 combinators.notPred! 257 ( 258 parsers.string_!"\n" 259 ), 260 parsers.anyChar!() 261 ) 262 ), 263 parsers.string_!"\n" 264 ) 265 ).build!(kind, SrcType).parse(input, caller); 266 } 267 } 268 } 269 270 debug(ctpg) unittest 271 { 272 273 with(parse!(lineComment!(), ParserKind!(true, true))("// comment\nnot comment")) 274 { 275 assert(match == true); 276 assert(value == None()); 277 assert(nextInput.source == "not comment"); 278 } 279 280 with(parse!(lineComment!(), ParserKind!(true, true))("// not terminated comment")) 281 { 282 assert(match == false); 283 assert(error.position == 25); 284 assert(error.msg == "'\n' expected"); 285 } 286 } 287 288 289 // 普通のコメントを消費するパーサ 290 template ordinaryComment() 291 { 292 template build(alias kind, SrcType) 293 { 294 mixin MAKE_RESULT!q{ None }; 295 296 Result parse(Input!SrcType input, in Caller caller) 297 { 298 return combinators.none! 299 ( 300 combinators.sequence! 301 ( 302 parsers.string_!"/*", 303 combinators.more0! 304 ( 305 combinators.sequence! 306 ( 307 combinators.notPred! 308 ( 309 parsers.string_!"*/" 310 ), 311 parsers.anyChar!() 312 ) 313 ), 314 parsers.string_!"*/" 315 ) 316 ).build!(kind, SrcType).parse(input, caller); 317 } 318 } 319 } 320 321 debug(ctpg) unittest 322 { 323 with(parse!(ordinaryComment!(), ParserKind!(true, true))("/* comment */not comment")) 324 { 325 assert(match == true); 326 assert(nextInput.source == "not comment"); 327 } 328 329 with(parse!(ordinaryComment!(), ParserKind!(true, true))("/* not terminated comment")) 330 { 331 assert(match == false); 332 assert(error.position == 25); 333 assert(error.msg == "'*/' expected"); 334 } 335 } 336 337 338 // ネストされたコメントを消費するパーサ 339 template nestedComment() 340 { 341 template build(alias kind, SrcType) 342 { 343 mixin MAKE_RESULT!q{ None }; 344 345 Result parse(Input!SrcType input, in Caller caller) 346 { 347 return combinators.none! 348 ( 349 combinators.sequence! 350 ( 351 parsers.string_!"/+", 352 combinators.more0! 353 ( 354 combinators.choice! 355 ( 356 nestedComment!(), 357 combinators.sequence! 358 ( 359 combinators.notPred! 360 ( 361 parsers.string_!"+/" 362 ), 363 parsers.anyChar!() 364 ) 365 ) 366 ), 367 parsers.string_!"+/" 368 ) 369 ).build!(kind, SrcType).parse(input, caller); 370 } 371 } 372 } 373 374 debug(ctpg) unittest 375 { 376 with(parse!(nestedComment!(), ParserKind!(true, true))("/+ comment +/not comment")) 377 { 378 assert(match == true); 379 assert(nextInput.source == "not comment"); 380 } 381 382 with(parse!(nestedComment!(), ParserKind!(true, true))("/+ comment /+ inner comment +/ comment +/not comment")) 383 { 384 assert(match == true); 385 assert(nextInput.source == "not comment"); 386 } 387 388 with(parse!(nestedComment!(), ParserKind!(true, true))("/+ not terminated comment")) 389 { 390 assert(match == false); 391 assert(error.position == 25); 392 assert(error.msg == "'+/' expected"); 393 } 394 } 395 396 397 // スキップされるべき空白を消費するパーサ 398 template spaces() 399 { 400 template build(alias kind, SrcType) 401 { 402 mixin MAKE_RESULT!q{ None }; 403 404 Result parse(Input!SrcType input, in Caller caller) 405 { 406 return combinators.none! 407 ( 408 combinators.more0! 409 ( 410 combinators.choice! 411 ( 412 parsers.string_!" ", 413 parsers.string_!"\n", 414 parsers.string_!"\t", 415 parsers.string_!"\r", 416 parsers.string_!"\f", 417 lineComment!(), 418 ordinaryComment!(), 419 nestedComment!() 420 ) 421 ) 422 ).build!(kind, SrcType).parse(input, caller); 423 } 424 } 425 } 426 427 debug(ctpg) unittest 428 { 429 with(parse!(spaces!(), ParserKind!(true, true))("/* a */// b \nc")) 430 { 431 assert(match == true); 432 assert(nextInput.source == "c"); 433 } 434 435 with(parse!(spaces!(), ParserKind!(true, true))("0/* a */// b \nc")) 436 { 437 assert(match == true); 438 assert(nextInput.source == "0/* a */// b \nc"); 439 } 440 } 441 442 443 template arch(string open, string close) 444 { 445 template build(alias kind, SrcType) 446 { 447 mixin MAKE_RESULT!q{ string }; 448 449 Result parse(Input!SrcType input, in Caller caller) 450 { 451 return combinators.inputSlice! 452 ( 453 combinators.sequence! 454 ( 455 parsers.string_!open, 456 combinators.more0! 457 ( 458 combinators.choice! 459 ( 460 arch!(open, close), 461 combinators.sequence! 462 ( 463 combinators.notPred! 464 ( 465 parsers.string_!close 466 ), 467 combinators.choice! 468 ( 469 stringLiteral!(), 470 parsers.anyChar!() 471 ) 472 ) 473 ) 474 ), 475 parsers.string_!close 476 ) 477 ).build!(kind, SrcType).parse(input, caller); 478 } 479 } 480 } 481 482 debug(ctpg) unittest 483 { 484 with(parse!(arch!("(", ")"), ParserKind!(true, true))("((a(b)c)d(e))f")) 485 { 486 assert(match == true); 487 assert(nextInput.source == "f"); 488 assert(value == "((a(b)c)d(e))"); 489 } 490 491 with(parse!(arch!("(", ")"), ParserKind!(true, true))("((a(b)c)d(e)")) 492 { 493 assert(match == false); 494 assert(error.position == 12); 495 assert(error.msg == "')' expected"); 496 } 497 } 498 499 500 template func() 501 { 502 template build(alias kind, SrcType) 503 { 504 mixin MAKE_RESULT!q{ Node }; 505 506 Result parse(Input!SrcType input, in Caller caller) 507 { 508 return ownCombinators.makeNode! 509 ( 510 combinators.inputSlice! 511 ( 512 combinators.sequence! 513 ( 514 combinators.option! 515 ( 516 arch!("(", ")") 517 ), 518 arch!("{", "}") 519 ) 520 ), 521 TokenType.CONVERTER 522 ).build!(kind, SrcType).parse(input, caller); 523 } 524 } 525 } 526 527 debug(ctpg) unittest 528 { 529 with(parse!(func!(), ParserKind!(true, true))(q"<(a, b, c){ return "{}" ~ r"{}" ~ `{}` ~ a ~ b ~ c; }>")) 530 { 531 assert(match == true); 532 assert(nextInput.source == ""); 533 assert(value.token.type == TokenType.CONVERTER); 534 assert(value.token.text == q"<(a, b, c){ return "{}" ~ r"{}" ~ `{}` ~ a ~ b ~ c; }>"); 535 assert(value.children.length == 0); 536 } 537 538 with(parse!(func!(), ParserKind!(true, true))(q"<(a, b, c{ return "{}" ~ r"{}" ~ `{}` ~ a ~ b ~ c; }>")) 539 { 540 assert(match == false); 541 assert(error.msg == "')' expected"); 542 assert(error.position == 51); 543 } 544 545 with(parse!(func!(), ParserKind!(true, true))(q"<(a, b, c){ return "{}" ~ r"{}" ~ `{}` ~ a ~ b ~ c; >")) 546 { 547 assert(match == false); 548 assert(error.msg == "'}' expected"); 549 assert(error.position == 51); 550 } 551 } 552 553 554 template id() 555 { 556 template build(alias kind, SrcType) 557 { 558 mixin MAKE_RESULT!q{ Node }; 559 560 Result parse(Input!string input, in Caller caller) 561 { 562 return ownCombinators.makeNode! 563 ( 564 combinators.changeError! 565 ( 566 identifier!(), 567 "identifier expected" 568 ), 569 TokenType.ID 570 ).build!(kind, SrcType).parse(input, caller); 571 } 572 } 573 } 574 575 debug(ctpg) unittest 576 { 577 with(parse!(id!(), ParserKind!(true, true))("_ab0=")) 578 { 579 assert(match == true); 580 assert(nextInput.source == "="); 581 assert(value.token.type == TokenType.ID); 582 assert(value.token.text == "_ab0"); 583 assert(value.children.length == 0); 584 } 585 586 with(parse!(id!(), ParserKind!(true, true))("__hogehoge12345678")) 587 { 588 assert(match == true); 589 assert(nextInput.source == ""); 590 assert(value.token.type == TokenType.ID); 591 assert(value.token.text == "__hogehoge12345678"); 592 assert(value.children.length == 0); 593 } 594 595 with(parse!(id!(), ParserKind!(true, true))("ああ")) 596 { 597 assert(match == false); 598 assert(error.msg == "identifier expected"); 599 assert(error.position == 0); 600 } 601 } 602 603 604 template nonterminal() 605 { 606 template build(alias kind, SrcType) 607 { 608 mixin MAKE_RESULT!q{ Node }; 609 610 Result parse(Input!string input, in Caller caller) 611 { 612 return ownCombinators.makeNode! 613 ( 614 combinators.changeError! 615 ( 616 identifier!(), 617 "identifier expected" 618 ), 619 TokenType.NONTERMINAL 620 ).build!(kind, SrcType).parse(input, caller); 621 } 622 } 623 } 624 625 debug(ctpg) unittest 626 { 627 with(parse!(nonterminal!(), ParserKind!(true, true))("_ab0=")) 628 { 629 assert(match == true); 630 assert(nextInput.source == "="); 631 assert(value.token.type == TokenType.NONTERMINAL); 632 assert(value.token.text == "_ab0"); 633 assert(value.children.length == 0); 634 } 635 636 with(parse!(nonterminal!(), ParserKind!(true, true))("__hogehoge12345678")) 637 { 638 assert(match == true); 639 assert(nextInput.source == ""); 640 assert(value.token.type == TokenType.NONTERMINAL); 641 assert(value.token.text == "__hogehoge12345678"); 642 assert(value.children.length == 0); 643 } 644 645 with(parse!(nonterminal!(), ParserKind!(true, true))("ああ")) 646 { 647 assert(match == false); 648 assert(error.msg == "identifier expected"); 649 assert(error.position == 0); 650 } 651 } 652 653 654 template typeName() 655 { 656 template build(alias kind, SrcType) 657 { 658 mixin MAKE_RESULT!q{ Node }; 659 660 Result parse(Input!SrcType input, in Caller caller) 661 { 662 return ownCombinators.makeNode! 663 ( 664 combinators.inputSlice! 665 ( 666 combinators.sequence! 667 ( 668 combinators.choice! 669 ( 670 parsers.charRange!('A','Z'), 671 parsers.charRange!('a','z'), 672 parsers.string_!"_" 673 ), 674 combinators.more0! 675 ( 676 combinators.choice! 677 ( 678 parsers.charRange!('0','9'), 679 parsers.charRange!('A','Z'), 680 parsers.charRange!('a','z'), 681 parsers.string_!"_", 682 parsers.string_!"!", 683 arch!("(", ")"), 684 arch!("[", "]") 685 ) 686 ) 687 ) 688 ), 689 TokenType.TEMPLATE_INSTANCE 690 ).build!(kind, SrcType).parse(input, caller); 691 } 692 } 693 } 694 695 debug(ctpg) unittest 696 { 697 with(parse!(typeName!(), ParserKind!(true, true))("hoge")) 698 { 699 assert(match == true); 700 assert(nextInput.source == ""); 701 assert(value.token.type == TokenType.TEMPLATE_INSTANCE); 702 assert(value.token.text == "hoge"); 703 assert(value.children.length == 0); 704 } 705 } 706 707 708 template eofLit() 709 { 710 template build(alias kind, SrcType) 711 { 712 mixin MAKE_RESULT!q{ Node }; 713 714 Result parse(Input!string input, in Caller caller) 715 { 716 return ownCombinators.makeNode! 717 ( 718 parsers.string_!"$", 719 TokenType.DOLLAR 720 ).build!(kind, SrcType).parse(input, caller); 721 } 722 } 723 } 724 725 debug(ctpg) unittest 726 { 727 with(parse!(eofLit!(), ParserKind!(true, true))("$")) 728 { 729 assert(match == true); 730 assert(nextInput.source == ""); 731 assert(value.token.type == TokenType.DOLLAR); 732 assert(value.token.text == "$"); 733 assert(value.children.length == 0); 734 } 735 736 with(parse!(eofLit!(), ParserKind!(true, true))("hoge")) 737 { 738 assert(match == false); 739 assert(error.msg == "'$' expected"); 740 assert(error.position == 0); 741 } 742 } 743 744 745 template rangeLitOneChar() 746 { 747 template build(alias kind, SrcType) 748 { 749 mixin MAKE_RESULT!q{ Node }; 750 751 Result parse(Input!SrcType input, in Caller caller) 752 { 753 return ownCombinators.makeNode! 754 ( 755 combinators.inputSlice! 756 ( 757 parsers.anyChar!() 758 ), 759 TokenType.RANGE_ONE_CHAR 760 ).build!(kind, SrcType).parse(input, caller); 761 } 762 } 763 } 764 765 debug(ctpg) unittest 766 { 767 with(parse!(rangeLitOneChar!(), ParserKind!(true, true))("a")) 768 { 769 assert(match == true); 770 assert(nextInput.source == ""); 771 assert(value.token.type == TokenType.RANGE_ONE_CHAR); 772 assert(value.token.text == "a"); 773 assert(value.children.length == 0); 774 } 775 776 with(parse!(rangeLitOneChar!(), ParserKind!(true, true))("鬱")) 777 { 778 assert(match == true); 779 assert(nextInput.source == ""); 780 assert(value.token.type == TokenType.RANGE_ONE_CHAR); 781 assert(value.token.text == "鬱"); 782 assert(value.children.length == 0); 783 } 784 } 785 786 787 template rangeLitCharRange() 788 { 789 template build(alias kind, SrcType) 790 { 791 mixin MAKE_RESULT!q{ Node }; 792 793 Result parse(Input!SrcType input, in Caller caller) 794 { 795 return ownCombinators.setInfo! 796 ( 797 combinators.convert! 798 ( 799 combinators.untuple! 800 ( 801 combinators.sequence! 802 ( 803 rangeLitOneChar!(), 804 combinators.none! 805 ( 806 parsers.string_!"-" 807 ), 808 rangeLitOneChar!() 809 ), 810 ), 811 (Node begin, Node end) => Node(Token(TokenType.RANGE_CHAR_RANGE, "-"), [begin, end]) 812 ) 813 ).build!(kind, SrcType).parse(input, caller); 814 } 815 } 816 } 817 818 debug(ctpg) unittest 819 { 820 with(parse!(rangeLitCharRange!(), ParserKind!(true, true))("a-z")) 821 { 822 assert(match == true); 823 assert(nextInput.source == ""); 824 assert(value.token.type == TokenType.RANGE_CHAR_RANGE); 825 assert(value.token.text == "-"); 826 assert(value.children.length == 2); 827 assert(value.children[0].token.type == TokenType.RANGE_ONE_CHAR); 828 assert(value.children[0].token.text == "a"); 829 assert(value.children[0].children.length == 0); 830 assert(value.children[1].token.type == TokenType.RANGE_ONE_CHAR); 831 assert(value.children[1].token.text == "z"); 832 assert(value.children[1].children.length == 0); 833 } 834 835 with(parse!(rangeLitCharRange!(), ParserKind!(true, true))("躁-鬱")) 836 { 837 assert(match == true); 838 assert(nextInput.source == ""); 839 assert(value.token.type == TokenType.RANGE_CHAR_RANGE); 840 assert(value.token.text == "-"); 841 assert(value.children.length == 2); 842 assert(value.children[0].token.type == TokenType.RANGE_ONE_CHAR); 843 assert(value.children[0].token.text == "躁"); 844 assert(value.children[0].children.length == 0); 845 assert(value.children[1].token.type == TokenType.RANGE_ONE_CHAR); 846 assert(value.children[1].token.text == "鬱"); 847 assert(value.children[1].children.length == 0); 848 } 849 } 850 851 852 template rangeLit() 853 { 854 template build(alias kind, SrcType) 855 { 856 mixin MAKE_RESULT!q{ Node }; 857 858 Result parse(Input!SrcType input, in Caller caller) 859 { 860 return ownCombinators.setInfo! 861 ( 862 combinators.convert! 863 ( 864 combinators.untuple! 865 ( 866 combinators.sequence! 867 ( 868 combinators.none! 869 ( 870 parsers.string_!"[" 871 ), 872 combinators.more1! 873 ( 874 combinators.untuple! 875 ( 876 combinators.sequence! 877 ( 878 combinators.notPred! 879 ( 880 parsers.string_!"]" 881 ), 882 combinators.choice! 883 ( 884 rangeLitCharRange!(), 885 rangeLitOneChar!() 886 ) 887 ) 888 ) 889 ), 890 combinators.none! 891 ( 892 parsers.string_!"]" 893 ) 894 ), 895 ), 896 (Node[] children) => Node(Token(TokenType.RANGE, "RANGE_LIT"), children) 897 ) 898 ).build!(kind, SrcType).parse(input, caller); 899 } 900 } 901 } 902 903 debug(ctpg) unittest 904 { 905 with(parse!(rangeLit!(), ParserKind!(true, true))("[a-zあ躁-鬱]")) 906 { 907 assert(match == true); 908 assert(nextInput.source == ""); 909 assert(value.token.type == TokenType.RANGE); 910 assert(value.token.text == "RANGE_LIT"); 911 assert(value.children.length == 3); 912 assert(value.children[0].token.type == TokenType.RANGE_CHAR_RANGE); 913 assert(value.children[0].token.text == "-"); 914 assert(value.children[0].children.length == 2); 915 assert(value.children[0].children[0].token.type == TokenType.RANGE_ONE_CHAR); 916 assert(value.children[0].children[0].token.text == "a"); 917 assert(value.children[0].children[0].children.length == 0); 918 assert(value.children[0].children[1].token.type == TokenType.RANGE_ONE_CHAR); 919 assert(value.children[0].children[1].token.text == "z"); 920 assert(value.children[0].children[1].children.length == 0); 921 assert(value.children[1].token.type == TokenType.RANGE_ONE_CHAR); 922 assert(value.children[1].token.text == "あ"); 923 assert(value.children[1].children.length == 0); 924 assert(value.children[2].token.type == TokenType.RANGE_CHAR_RANGE); 925 assert(value.children[2].token.text == "-"); 926 assert(value.children[2].children.length == 2); 927 assert(value.children[2].children[0].token.type == TokenType.RANGE_ONE_CHAR); 928 assert(value.children[2].children[0].token.text == "躁"); 929 assert(value.children[2].children[0].children.length == 0); 930 assert(value.children[2].children[1].token.type == TokenType.RANGE_ONE_CHAR); 931 assert(value.children[2].children[1].token.text == "鬱"); 932 assert(value.children[2].children[1].children.length == 0); 933 } 934 } 935 936 937 template stringLit() 938 { 939 template build(alias kind, SrcType) 940 { 941 mixin MAKE_RESULT!q{ Node }; 942 943 Result parse(Input!SrcType input, in Caller caller) 944 { 945 return ownCombinators.makeNode! 946 ( 947 stringLiteral!(), 948 TokenType.STRING 949 ).build!(kind, SrcType).parse(input, caller); 950 } 951 } 952 } 953 954 debug(ctpg) unittest 955 { 956 with(parse!(stringLit!(), ParserKind!(true, true))(q{"hoge"})) 957 { 958 assert(match == true); 959 assert(nextInput.source == ""); 960 assert(value.token.type == TokenType.STRING); 961 assert(value.token.text == q{"hoge"}); 962 assert(value.children.length == 0); 963 } 964 965 with(parse!(stringLit!(), ParserKind!(true, true))(q{r"hoge\"})) 966 { 967 assert(match == true); 968 assert(nextInput.source == ""); 969 assert(value.token.type == TokenType.STRING); 970 assert(value.token.text == q{r"hoge\"}); 971 assert(value.children.length == 0); 972 } 973 974 with(parse!(stringLit!(), ParserKind!(true, true))(q{`"hoge"`})) 975 { 976 assert(match == true); 977 assert(nextInput.source == ""); 978 assert(value.token.type == TokenType.STRING); 979 assert(value.token.text == q{`"hoge"`}); 980 assert(value.children.length == 0); 981 } 982 } 983 984 985 template literal() 986 { 987 template build(alias kind, SrcType) 988 { 989 mixin MAKE_RESULT!q{ Node }; 990 991 Result parse(Input!SrcType input, in Caller caller) 992 { 993 return combinators.choice! 994 ( 995 eofLit!(), 996 rangeLit!(), 997 stringLit!() 998 ).build!(kind, SrcType).parse(input, caller); 999 } 1000 } 1001 } 1002 1003 debug(ctpg) unittest 1004 { 1005 with(parse!(literal!(), ParserKind!(true, true))("$")) 1006 { 1007 assert(match == true); 1008 assert(nextInput.source == ""); 1009 assert(value.token.type == TokenType.DOLLAR); 1010 assert(value.token.text == "$"); 1011 assert(value.children.length == 0); 1012 } 1013 1014 with(parse!(literal!(), ParserKind!(true, true))("[a-zあ躁-鬱]")) 1015 { 1016 assert(match == true); 1017 assert(nextInput.source == ""); 1018 assert(value.token.type == TokenType.RANGE); 1019 assert(value.token.text == "RANGE_LIT"); 1020 assert(value.children.length == 3); 1021 assert(value.children[0].token.type == TokenType.RANGE_CHAR_RANGE); 1022 assert(value.children[0].token.text == "-"); 1023 assert(value.children[0].children.length == 2); 1024 assert(value.children[0].children[0].token.type == TokenType.RANGE_ONE_CHAR); 1025 assert(value.children[0].children[0].token.text == "a"); 1026 assert(value.children[0].children[0].children.length == 0); 1027 assert(value.children[0].children[1].token.type == TokenType.RANGE_ONE_CHAR); 1028 assert(value.children[0].children[1].token.text == "z"); 1029 assert(value.children[0].children[1].children.length == 0); 1030 assert(value.children[1].token.type == TokenType.RANGE_ONE_CHAR); 1031 assert(value.children[1].token.text == "あ"); 1032 assert(value.children[1].children.length == 0); 1033 assert(value.children[2].token.type == TokenType.RANGE_CHAR_RANGE); 1034 assert(value.children[2].token.text == "-"); 1035 assert(value.children[2].children.length == 2); 1036 assert(value.children[2].children[0].token.type == TokenType.RANGE_ONE_CHAR); 1037 assert(value.children[2].children[0].token.text == "躁"); 1038 assert(value.children[2].children[0].children.length == 0); 1039 assert(value.children[2].children[1].token.type == TokenType.RANGE_ONE_CHAR); 1040 assert(value.children[2].children[1].token.text == "鬱"); 1041 assert(value.children[2].children[1].children.length == 0); 1042 } 1043 1044 with(parse!(literal!(), ParserKind!(true, true))(q{"hoge"})) 1045 { 1046 assert(match == true); 1047 assert(nextInput.source == ""); 1048 assert(value.token.type == TokenType.STRING); 1049 assert(value.token.text == q{"hoge"}); 1050 assert(value.children.length == 0); 1051 } 1052 1053 with(parse!(literal!(), ParserKind!(true, true))(q{r"hoge\"})) 1054 { 1055 assert(match == true); 1056 assert(nextInput.source == ""); 1057 assert(value.token.type == TokenType.STRING); 1058 assert(value.token.text == q{r"hoge\"}); 1059 assert(value.children.length == 0); 1060 } 1061 1062 with(parse!(literal!(), ParserKind!(true, true))(q{`"hoge"`})) 1063 { 1064 assert(match == true); 1065 assert(nextInput.source == ""); 1066 assert(value.token.type == TokenType.STRING); 1067 assert(value.token.text == q{`"hoge"`}); 1068 assert(value.children.length == 0); 1069 } 1070 1071 with(parse!(literal!(), ParserKind!(true, true))("hoge")) 1072 { 1073 assert(match == false); 1074 assert(error.msg == "'\"' expected"); 1075 assert(error.position == 0); 1076 } 1077 } 1078 1079 1080 template primaryExp() 1081 { 1082 template build(alias kind, SrcType) 1083 { 1084 mixin MAKE_RESULT!q{ Node }; 1085 1086 Result parse(Input!SrcType input, in Caller caller) 1087 { 1088 return combinators.choice! 1089 ( 1090 stringLit!(), 1091 rangeLit!(), 1092 eofLit!(), 1093 combinators.untuple! 1094 ( 1095 combinators.sequence! 1096 ( 1097 combinators.none! 1098 ( 1099 parsers.string_!"(" 1100 ), 1101 spaces!(), 1102 choiceExp!(), 1103 spaces!(), 1104 combinators.none! 1105 ( 1106 parsers.string_!")" 1107 ) 1108 ) 1109 ), 1110 nonterminal!() 1111 ).build!(kind, SrcType).parse(input, caller); 1112 } 1113 } 1114 } 1115 1116 debug(ctpg) unittest 1117 { 1118 with(parse!(primaryExp!(), ParserKind!(true, true))("$")) 1119 { 1120 assert(match == true); 1121 assert(nextInput.source == ""); 1122 assert(value.token.type == TokenType.DOLLAR); 1123 assert(value.token.text == "$"); 1124 assert(value.children.length == 0); 1125 } 1126 1127 with(parse!(primaryExp!(), ParserKind!(true, true))("($)")) 1128 { 1129 assert(match == true); 1130 assert(nextInput.source == ""); 1131 assert(value.token.type == TokenType.DOLLAR); 1132 assert(value.token.text == "$"); 1133 assert(value.children.length == 0); 1134 } 1135 1136 with(parse!(primaryExp!(), ParserKind!(true, true))("_ab0=")) 1137 { 1138 assert(match == true); 1139 assert(nextInput.source == "="); 1140 assert(value.token.type == TokenType.NONTERMINAL); 1141 assert(value.token.text == "_ab0"); 1142 assert(value.children.length == 0); 1143 } 1144 } 1145 1146 1147 template preExp() 1148 { 1149 template build(alias kind, SrcType) 1150 { 1151 mixin MAKE_RESULT!q{ Node }; 1152 1153 Result parse(Input!SrcType input, in Caller caller) 1154 { 1155 return combinators.convert! 1156 ( 1157 combinators.sequence! 1158 ( 1159 combinators.option! 1160 ( 1161 combinators.choice! 1162 ( 1163 parsers.string_!"!", 1164 parsers.string_!"&", 1165 parsers.string_!"^" 1166 ) 1167 ), 1168 primaryExp!(), 1169 ), 1170 function(Option!string op, Node primaryExp) 1171 { 1172 if(op.some) 1173 { 1174 Node preExp; 1175 1176 final switch(op.value) 1177 { 1178 case "!": 1179 preExp.token.type = TokenType.EXCLAM; 1180 break; 1181 case "&": 1182 preExp.token.type = TokenType.ANPERSAND; 1183 break; 1184 case "^": 1185 preExp.token.type = TokenType.ASCIICIRCUM; 1186 break; 1187 } 1188 preExp.token.text = op; 1189 preExp.children ~= primaryExp; 1190 1191 return preExp; 1192 } 1193 else 1194 { 1195 return primaryExp; 1196 } 1197 } 1198 ).build!(kind, SrcType).parse(input, caller); 1199 } 1200 } 1201 } 1202 1203 debug(ctpg) unittest 1204 { 1205 with(parse!(preExp!(), ParserKind!(true, true))("!$")) 1206 { 1207 assert(match == true); 1208 assert(nextInput.source == ""); 1209 assert(value.token.type == TokenType.EXCLAM); 1210 assert(value.token.text == "!"); 1211 assert(value.children.length == 1); 1212 assert(value.children[0].token.type == TokenType.DOLLAR); 1213 assert(value.children[0].token.text == "$"); 1214 assert(value.children[0].children.length == 0); 1215 } 1216 1217 with(parse!(preExp!(), ParserKind!(true, true))("&$")) 1218 { 1219 assert(match == true); 1220 assert(nextInput.source == ""); 1221 assert(value.token.type == TokenType.ANPERSAND); 1222 assert(value.token.text == "&"); 1223 assert(value.children.length == 1); 1224 assert(value.children[0].token.type == TokenType.DOLLAR); 1225 assert(value.children[0].token.text == "$"); 1226 assert(value.children[0].children.length == 0); 1227 } 1228 1229 with(parse!(preExp!(), ParserKind!(true, true))("^$")) 1230 { 1231 assert(match == true); 1232 assert(nextInput.source == ""); 1233 assert(value.token.type == TokenType.ASCIICIRCUM); 1234 assert(value.token.text == "^"); 1235 assert(value.children.length == 1); 1236 assert(value.children[0].token.type == TokenType.DOLLAR); 1237 assert(value.children[0].token.text == "$"); 1238 assert(value.children[0].children.length == 0); 1239 } 1240 1241 with(parse!(preExp!(), ParserKind!(true, true))("$")) 1242 { 1243 assert(match == true); 1244 assert(nextInput.source == ""); 1245 assert(value.token.type == TokenType.DOLLAR); 1246 assert(value.token.text == "$"); 1247 assert(value.children.length == 0); 1248 } 1249 } 1250 1251 1252 template postExp() 1253 { 1254 template build(alias kind, SrcType) 1255 { 1256 mixin MAKE_RESULT!q{ Node }; 1257 1258 Result parse(Input!SrcType input, in Caller caller) 1259 { 1260 return combinators.convert! 1261 ( 1262 combinators.sequence! 1263 ( 1264 preExp!(), 1265 combinators.option! 1266 ( 1267 combinators.sequence! 1268 ( 1269 combinators.choice! 1270 ( 1271 parsers.string_!"*", 1272 parsers.string_!"+", 1273 ), 1274 combinators.option! 1275 ( 1276 combinators.untuple! 1277 ( 1278 combinators.sequence! 1279 ( 1280 combinators.none! 1281 ( 1282 parsers.string_!"<" 1283 ), 1284 choiceExp!(), 1285 combinators.none! 1286 ( 1287 parsers.string_!">" 1288 ) 1289 ) 1290 ) 1291 ) 1292 ) 1293 ) 1294 ), 1295 function(Node preExp, Option!(Tuple!(string, Option!Node)) op) 1296 { 1297 if(op.some) 1298 { 1299 Node postExp; 1300 1301 final switch(op[0]) 1302 { 1303 case "*": 1304 postExp.token.type = TokenType.ASTERISK; 1305 break; 1306 case "+": 1307 postExp.token.type = TokenType.PLUS; 1308 break; 1309 } 1310 1311 postExp.token.text = op[0]; 1312 postExp.children ~= preExp; 1313 1314 if(op[1].some) 1315 { 1316 postExp.children ~= op[1]; 1317 } 1318 1319 return postExp; 1320 } 1321 else 1322 { 1323 return preExp; 1324 } 1325 } 1326 ).build!(kind, SrcType).parse(input, caller); 1327 } 1328 } 1329 } 1330 1331 debug(ctpg) unittest 1332 { 1333 with(parse!(postExp!(), ParserKind!(true, true))("$*")) 1334 { 1335 assert(match == true); 1336 assert(nextInput.source == ""); 1337 assert(value.token.type == TokenType.ASTERISK); 1338 assert(value.token.text == "*"); 1339 assert(value.children.length == 1); 1340 assert(value.children[0].token.type == TokenType.DOLLAR); 1341 assert(value.children[0].token.text == "$"); 1342 assert(value.children[0].children.length == 0); 1343 } 1344 1345 with(parse!(postExp!(), ParserKind!(true, true))("$+")) 1346 { 1347 assert(match == true); 1348 assert(nextInput.source == ""); 1349 assert(value.token.type == TokenType.PLUS); 1350 assert(value.token.text == "+"); 1351 assert(value.children.length == 1); 1352 assert(value.children[0].token.type == TokenType.DOLLAR); 1353 assert(value.children[0].token.text == "$"); 1354 assert(value.children[0].children.length == 0); 1355 } 1356 1357 with(parse!(postExp!(), ParserKind!(true, true))("$*<$>")) 1358 { 1359 assert(match == true); 1360 assert(nextInput.source == ""); 1361 assert(value.token.type == TokenType.ASTERISK); 1362 assert(value.token.text == "*"); 1363 assert(value.children.length == 2); 1364 assert(value.children[0].token.type == TokenType.DOLLAR); 1365 assert(value.children[0].token.text == "$"); 1366 assert(value.children[0].children.length == 0); 1367 assert(value.children[1].token.type == TokenType.DOLLAR); 1368 assert(value.children[1].token.text == "$"); 1369 assert(value.children[1].children.length == 0); 1370 } 1371 1372 with(parse!(postExp!(), ParserKind!(true, true))("$+<$>")) 1373 { 1374 assert(match == true); 1375 assert(nextInput.source == ""); 1376 assert(value.token.type == TokenType.PLUS); 1377 assert(value.token.text == "+"); 1378 assert(value.children.length == 2); 1379 assert(value.children[0].token.type == TokenType.DOLLAR); 1380 assert(value.children[0].token.text == "$"); 1381 assert(value.children[0].children.length == 0); 1382 assert(value.children[1].token.type == TokenType.DOLLAR); 1383 assert(value.children[1].token.text == "$"); 1384 assert(value.children[1].children.length == 0); 1385 } 1386 } 1387 1388 1389 template optionExp() 1390 { 1391 template build(alias kind, SrcType) 1392 { 1393 mixin MAKE_RESULT!q{ Node }; 1394 1395 Result parse(Input!SrcType input, in Caller caller) 1396 { 1397 return combinators.convert! 1398 ( 1399 combinators.sequence! 1400 ( 1401 postExp!(), 1402 combinators.option! 1403 ( 1404 combinators.none! 1405 ( 1406 parsers.string_!"?" 1407 ) 1408 ) 1409 ), 1410 function(Node postExp, Option!None op) 1411 { 1412 if(op.some) 1413 { 1414 Node optionExp; 1415 1416 optionExp.token.type = TokenType.QUESTION; 1417 optionExp.token.text = "?"; 1418 optionExp.children ~= postExp; 1419 1420 return optionExp; 1421 } 1422 else 1423 { 1424 return postExp; 1425 } 1426 } 1427 ).build!(kind, SrcType).parse(input, caller); 1428 } 1429 } 1430 } 1431 1432 debug(ctpg) unittest 1433 { 1434 with(parse!(optionExp!(), ParserKind!(true, true))("$?")) 1435 { 1436 assert(match == true); 1437 assert(nextInput.source == ""); 1438 assert(value.token.type == TokenType.QUESTION); 1439 assert(value.token.text == "?"); 1440 assert(value.children.length == 1); 1441 assert(value.children[0].token.type == TokenType.DOLLAR); 1442 assert(value.children[0].token.text == "$"); 1443 assert(value.children[0].children.length == 0); 1444 } 1445 } 1446 1447 1448 template seqExp() 1449 { 1450 template build(alias kind, SrcType) 1451 { 1452 mixin MAKE_RESULT!q{ Node }; 1453 1454 Result parse(Input!SrcType input, in Caller caller) 1455 { 1456 return combinators.convert! 1457 ( 1458 combinators.more1! 1459 ( 1460 optionExp!(), 1461 spaces!() 1462 ), 1463 function(Node[] optionExps) 1464 { 1465 if(optionExps.length > 1) 1466 { 1467 Node seqExp; 1468 1469 seqExp.token.type = TokenType.SEQUENCE; 1470 seqExp.token.text = "SEQ"; 1471 seqExp.children = optionExps; 1472 1473 return seqExp; 1474 } 1475 else 1476 { 1477 return optionExps[0]; 1478 } 1479 } 1480 ).build!(kind, SrcType).parse(input, caller); 1481 } 1482 } 1483 } 1484 1485 debug(ctpg) unittest 1486 { 1487 with(parse!(seqExp!(), ParserKind!(true, true))("$")) 1488 { 1489 assert(match == true); 1490 assert(nextInput.source == ""); 1491 assert(value.token.type == TokenType.DOLLAR); 1492 assert(value.token.text == "$"); 1493 assert(value.children.length == 0); 1494 } 1495 1496 with(parse!(seqExp!(), ParserKind!(true, true))("$ $")) 1497 { 1498 assert(match == true); 1499 assert(nextInput.source == ""); 1500 assert(value.token.type == TokenType.SEQUENCE); 1501 assert(value.token.text == "SEQ"); 1502 assert(value.children.length == 2); 1503 assert(value.children[0].token.type == TokenType.DOLLAR); 1504 assert(value.children[0].token.text == "$"); 1505 assert(value.children[0].children.length == 0); 1506 assert(value.children[1].token.type == TokenType.DOLLAR); 1507 assert(value.children[1].token.text == "$"); 1508 assert(value.children[1].children.length == 0); 1509 } 1510 } 1511 1512 1513 template convExp() 1514 { 1515 template build(alias kind, SrcType) 1516 { 1517 mixin MAKE_RESULT!q{ Node }; 1518 1519 Result parse(Input!SrcType input, in Caller caller) 1520 { 1521 return combinators.convert! 1522 ( 1523 combinators.sequence! 1524 ( 1525 seqExp!(), 1526 combinators.more0! 1527 ( 1528 combinators.untuple! 1529 ( 1530 combinators.sequence! 1531 ( 1532 spaces!(), 1533 parsers.getLine!(), 1534 parsers.getCallerLine!(), 1535 parsers.getCallerFile!(), 1536 combinators.choice! 1537 ( 1538 parsers.string_!">?", 1539 parsers.string_!">>" 1540 ), 1541 spaces!(), 1542 combinators.choice! 1543 ( 1544 func!(), 1545 typeName!() 1546 ) 1547 ) 1548 ) 1549 ) 1550 ), 1551 function(Node seqExp, Tuple!(size_t, size_t, string, string, Node)[] funcs) 1552 { 1553 Node result = seqExp; 1554 1555 foreach(func; funcs) 1556 { 1557 Node node; 1558 1559 size_t line = func[0]; 1560 size_t callerLine = func[1]; 1561 string callerFile = func[2]; 1562 string op = func[3]; 1563 Node funcNode = func[4]; 1564 1565 node.token.type = op == ">>" ? TokenType.LEFT_SHIFT : TokenType.LEFT_QUESTION; 1566 node.token.text = op; 1567 node.children ~= result; 1568 node.children ~= funcNode; 1569 node.line = line + callerLine + 1; 1570 node.file = callerFile; 1571 1572 result = node; 1573 } 1574 1575 return result; 1576 } 1577 ).build!(kind, SrcType).parse(input, caller); 1578 } 1579 } 1580 } 1581 1582 debug(ctpg) unittest 1583 { 1584 with(parse!(convExp!(), ParserKind!(true, true))("$")) 1585 { 1586 assert(match == true); 1587 assert(nextInput.source == ""); 1588 assert(value.token.type == TokenType.DOLLAR); 1589 assert(value.token.text == "$"); 1590 assert(value.children.length == 0); 1591 } 1592 1593 with(parse!(convExp!(), ParserKind!(true, true))("$ >> hoge")) 1594 { 1595 assert(match == true); 1596 assert(nextInput.source == ""); 1597 assert(value.token.type == TokenType.LEFT_SHIFT); 1598 assert(value.token.text == ">>"); 1599 assert(value.line == __LINE__ - 5); 1600 assert(value.file == __FILE__); 1601 assert(value.children.length == 2); 1602 assert(value.children[0].token.type == TokenType.DOLLAR); 1603 assert(value.children[0].token.text == "$"); 1604 assert(value.children[0].children.length == 0); 1605 assert(value.children[1].token.type == TokenType.TEMPLATE_INSTANCE); 1606 assert(value.children[1].token.text == "hoge"); 1607 assert(value.children[1].children.length == 0); 1608 } 1609 1610 with(parse!(convExp!(), ParserKind!(true, true))("$ >> hoge >> piyo")) 1611 { 1612 assert(match == true); 1613 assert(nextInput.source == ""); 1614 assert(value.token.type == TokenType.LEFT_SHIFT); 1615 assert(value.token.text == ">>"); 1616 assert(value.line == __LINE__ - 5); 1617 assert(value.file == __FILE__); 1618 assert(value.children.length == 2); 1619 assert(value.children[0].token.type == TokenType.LEFT_SHIFT); 1620 assert(value.children[0].token.text == ">>"); 1621 assert(value.children[0].line == __LINE__ - 10); 1622 assert(value.children[0].file == __FILE__); 1623 assert(value.children[0].children.length == 2); 1624 assert(value.children[0].children[0].token.type == TokenType.DOLLAR); 1625 assert(value.children[0].children[0].token.text == "$"); 1626 assert(value.children[0].children[0].children.length == 0); 1627 assert(value.children[0].children[1].token.type == TokenType.TEMPLATE_INSTANCE); 1628 assert(value.children[0].children[1].token.text == "hoge"); 1629 assert(value.children[0].children[1].children.length == 0); 1630 assert(value.children[1].token.type == TokenType.TEMPLATE_INSTANCE); 1631 assert(value.children[1].token.text == "piyo"); 1632 assert(value.children[1].children.length == 0); 1633 } 1634 1635 with(parse!(convExp!(), ParserKind!(true, true))("$ >> hoge >? piyo")) 1636 { 1637 assert(match == true); 1638 assert(nextInput.source == ""); 1639 assert(value.token.type == TokenType.LEFT_QUESTION); 1640 assert(value.token.text == ">?"); 1641 assert(value.children.length == 2); 1642 assert(value.children[0].token.type == TokenType.LEFT_SHIFT); 1643 assert(value.children[0].token.text == ">>"); 1644 assert(value.children[0].children.length == 2); 1645 assert(value.children[0].children[0].token.type == TokenType.DOLLAR); 1646 assert(value.children[0].children[0].token.text == "$"); 1647 assert(value.children[0].children[0].children.length == 0); 1648 assert(value.children[0].children[1].token.type == TokenType.TEMPLATE_INSTANCE); 1649 assert(value.children[0].children[1].token.text == "hoge"); 1650 assert(value.children[0].children[1].children.length == 0); 1651 assert(value.children[1].token.type == TokenType.TEMPLATE_INSTANCE); 1652 assert(value.children[1].token.text == "piyo"); 1653 assert(value.children[1].children.length == 0); 1654 } 1655 1656 with(parse!(convExp!(), ParserKind!(true, true))("$ >> (a, b){ return a + b; }")) 1657 { 1658 assert(match == true); 1659 assert(nextInput.source == ""); 1660 assert(value.token.type == TokenType.LEFT_SHIFT); 1661 assert(value.token.text == ">>"); 1662 assert(value.children.length == 2); 1663 assert(value.children[0].token.type == TokenType.DOLLAR); 1664 assert(value.children[0].token.text == "$"); 1665 assert(value.children[0].children.length == 0); 1666 assert(value.children[1].token.type == TokenType.CONVERTER); 1667 assert(value.children[1].token.text == q{(a, b){ return a + b; }}); 1668 assert(value.children[1].children.length == 0); 1669 } 1670 } 1671 1672 1673 template choiceExp() 1674 { 1675 template build(alias kind, SrcType) 1676 { 1677 mixin MAKE_RESULT!q{ Node }; 1678 1679 Result parse(Input!SrcType input, in Caller caller) 1680 { 1681 return combinators.convert! 1682 ( 1683 combinators.sequence! 1684 ( 1685 spaces!(), 1686 parsers.getLine!(), 1687 parsers.getCallerLine!(), 1688 parsers.getCallerFile!(), 1689 combinators.more1! 1690 ( 1691 convExp!(), 1692 combinators.sequence! 1693 ( 1694 spaces!(), 1695 parsers.string_!"/", 1696 spaces!() 1697 ) 1698 ) 1699 ), 1700 function(size_t line, size_t callerLine, string callerFile, Node[] convExps) 1701 { 1702 if(convExps.length > 1) 1703 { 1704 Node choiceExp; 1705 1706 choiceExp.token.type = TokenType.SLASH; 1707 choiceExp.token.text = "/"; 1708 choiceExp.children = convExps; 1709 choiceExp.line = line + callerLine + 1; 1710 choiceExp.file = callerFile; 1711 1712 return choiceExp; 1713 } 1714 else 1715 { 1716 return convExps[0]; 1717 } 1718 } 1719 ).build!(kind, SrcType).parse(input, caller); 1720 } 1721 } 1722 } 1723 1724 debug(ctpg) unittest 1725 { 1726 with(parse!(choiceExp!(), ParserKind!(true, true))("$")) 1727 { 1728 assert(match == true); 1729 assert(nextInput.source == ""); 1730 assert(value.token.type == TokenType.DOLLAR); 1731 assert(value.token.text == "$"); 1732 assert(value.children.length == 0); 1733 } 1734 1735 with(parse!(choiceExp!(), ParserKind!(true, true))("$ ")) 1736 { 1737 assert(match == true); 1738 assert(nextInput.source == " "); 1739 assert(value.token.type == TokenType.DOLLAR); 1740 assert(value.token.text == "$"); 1741 assert(value.children.length == 0); 1742 } 1743 1744 with(parse!(choiceExp!(), ParserKind!(true, true))("$ / $")) 1745 { 1746 assert(match == true); 1747 assert(nextInput.source == ""); 1748 assert(value.token.type == TokenType.SLASH); 1749 assert(value.token.text == "/"); 1750 assert(value.children.length == 2); 1751 assert(value.children[0].token.type == TokenType.DOLLAR); 1752 assert(value.children[0].token.text == "$"); 1753 assert(value.children[0].children.length == 0); 1754 assert(value.children[1].token.type == TokenType.DOLLAR); 1755 assert(value.children[1].token.text == "$"); 1756 assert(value.children[1].children.length == 0); 1757 } 1758 } 1759 1760 1761 template def() 1762 { 1763 template build(alias kind, SrcType) 1764 { 1765 mixin MAKE_RESULT!q{ Node }; 1766 1767 Result parse(Input!SrcType input, in Caller caller) 1768 { 1769 return combinators.convert! 1770 ( 1771 combinators.sequence! 1772 ( 1773 combinators.option! 1774 ( 1775 combinators.untuple! 1776 ( 1777 combinators.sequence! 1778 ( 1779 combinators.none! 1780 ( 1781 parsers.string_!"@setSkip(", 1782 ), 1783 spaces!(), 1784 choiceExp!(), 1785 spaces!(), 1786 combinators.none! 1787 ( 1788 parsers.string_!")" 1789 ), 1790 spaces!() 1791 ) 1792 ) 1793 ), 1794 typeName!(), 1795 spaces!(), 1796 id!(), 1797 spaces!(), 1798 combinators.none! 1799 ( 1800 parsers.string_!"=" 1801 ), 1802 spaces!(), 1803 choiceExp!(), 1804 spaces!(), 1805 combinators.none! 1806 ( 1807 parsers.string_!";" 1808 ) 1809 ), 1810 function(Option!Node skip, Node type, Node name, Node choiceExp) 1811 { 1812 Node def; 1813 1814 def.token.type = TokenType.DEFINITION; 1815 def.children ~= type; 1816 def.children ~= name; 1817 1818 if(skip.some) 1819 { 1820 Node skipNode; 1821 1822 skipNode.token.type = TokenType.SET_SKIP; 1823 skipNode.children ~= skip; 1824 skipNode.children ~= choiceExp; 1825 1826 def.children ~= skipNode; 1827 } 1828 else 1829 { 1830 def.children ~= choiceExp; 1831 } 1832 1833 return def; 1834 } 1835 ).build!(kind, SrcType).parse(input, caller); 1836 } 1837 } 1838 } 1839 1840 debug(ctpg) unittest 1841 { 1842 with(parse!(def!(), ParserKind!(true, true))(q{int hoge = $;})) 1843 { 1844 assert(match == true); 1845 assert(nextInput.source == ""); 1846 assert(value.token.type == TokenType.DEFINITION); 1847 assert(value.children.length == 3); 1848 assert(value.children[0].token.type == TokenType.TEMPLATE_INSTANCE); 1849 assert(value.children[0].token.text == "int"); 1850 assert(value.children[0].children.length == 0); 1851 assert(value.children[1].token.type == TokenType.ID); 1852 assert(value.children[1].token.text == "hoge"); 1853 assert(value.children[1].children.length == 0); 1854 assert(value.children[2].token.type == TokenType.DOLLAR); 1855 assert(value.children[2].token.text == "$"); 1856 assert(value.children[2].children.length == 0); 1857 } 1858 1859 with(parse!(def!(), ParserKind!(true, true))(q{@setSkip($) int hoge = $;})) 1860 { 1861 assert(match == true); 1862 assert(nextInput.source == ""); 1863 assert(value.token.type == TokenType.DEFINITION); 1864 assert(value.children.length == 3); 1865 assert(value.children[0].token.type == TokenType.TEMPLATE_INSTANCE); 1866 assert(value.children[0].token.text == "int"); 1867 assert(value.children[0].children.length == 0); 1868 assert(value.children[1].token.type == TokenType.ID); 1869 assert(value.children[1].token.text == "hoge"); 1870 assert(value.children[1].children.length == 0); 1871 assert(value.children[2].token.type == TokenType.SET_SKIP); 1872 assert(value.children[2].children.length == 2); 1873 assert(value.children[2].children[0].token.type == TokenType.DOLLAR); 1874 assert(value.children[2].children[0].token.text == "$"); 1875 assert(value.children[2].children[0].children.length == 0); 1876 assert(value.children[2].children[1].token.type == TokenType.DOLLAR); 1877 assert(value.children[2].children[1].token.text == "$"); 1878 assert(value.children[2].children[1].children.length == 0); 1879 } 1880 } 1881 1882 1883 template defaultSkip() 1884 { 1885 template build(alias kind, SrcType) 1886 { 1887 mixin MAKE_RESULT!q{ Node }; 1888 1889 Result parse(Input!SrcType input, in Caller caller) 1890 { 1891 return combinators.convert! 1892 ( 1893 combinators.untuple! 1894 ( 1895 combinators.sequence! 1896 ( 1897 combinators.none! 1898 ( 1899 parsers.string_!"@_setSkip(" 1900 ), 1901 spaces!(), 1902 choiceExp!(), 1903 spaces!(), 1904 combinators.none! 1905 ( 1906 parsers.string_!")" 1907 ) 1908 ) 1909 ), 1910 function(Node skip) 1911 { 1912 Node setSkipNode; 1913 1914 setSkipNode.token.type = TokenType.GLOBAL_SET_SKIP; 1915 setSkipNode.children ~= skip; 1916 1917 return setSkipNode; 1918 } 1919 ).build!(kind, SrcType).parse(input, caller); 1920 } 1921 } 1922 } 1923 1924 1925 template defs() 1926 { 1927 template build(alias kind, SrcType) 1928 { 1929 mixin MAKE_RESULT!q{ Node }; 1930 1931 Result parse(Input!SrcType input, in Caller caller) 1932 { 1933 return combinators.convert! 1934 ( 1935 combinators.untuple! 1936 ( 1937 combinators.sequence! 1938 ( 1939 spaces!(), 1940 combinators.more0! 1941 ( 1942 combinators.choice! 1943 ( 1944 defaultSkip!(), 1945 def!() 1946 ), 1947 spaces!() 1948 ), 1949 spaces!(), 1950 parsers.eof!() 1951 ) 1952 ), 1953 function(Node[] nodes) 1954 { 1955 Node defs; 1956 1957 defs.token.type = TokenType.DEFINITIONS; 1958 defs.children = nodes; 1959 1960 return defs; 1961 } 1962 ).build!(kind, SrcType).parse(input, caller); 1963 } 1964 } 1965 } 1966 1967 debug(ctpg) unittest 1968 { 1969 with(parse!(defs!(), ParserKind!(true, true))(q{int hoge = $; int piyo = $;})) 1970 { 1971 assert(match == true); 1972 assert(nextInput.source == ""); 1973 assert(value.token.type == TokenType.DEFINITIONS); 1974 assert(value.children.length == 2); 1975 assert(value.children[0].token.type == TokenType.DEFINITION); 1976 assert(value.children[0].children.length == 3); 1977 assert(value.children[0].children[0].token.type == TokenType.TEMPLATE_INSTANCE); 1978 assert(value.children[0].children[0].token.text == "int"); 1979 assert(value.children[0].children[0].children.length == 0); 1980 assert(value.children[0].children[1].token.type == TokenType.ID); 1981 assert(value.children[0].children[1].token.text == "hoge"); 1982 assert(value.children[0].children[1].children.length == 0); 1983 assert(value.children[0].children[2].token.type == TokenType.DOLLAR); 1984 assert(value.children[0].children[2].token.text == "$"); 1985 assert(value.children[0].children[2].children.length == 0); 1986 assert(value.children[1].token.type == TokenType.DEFINITION); 1987 assert(value.children[1].children.length == 3); 1988 assert(value.children[1].children[0].token.type == TokenType.TEMPLATE_INSTANCE); 1989 assert(value.children[1].children[0].token.text == "int"); 1990 assert(value.children[1].children[0].children.length == 0); 1991 assert(value.children[1].children[1].token.type == TokenType.ID); 1992 assert(value.children[1].children[1].token.text == "piyo"); 1993 assert(value.children[1].children[1].children.length == 0); 1994 assert(value.children[1].children[2].token.type == TokenType.DOLLAR); 1995 assert(value.children[1].children[2].token.text == "$"); 1996 assert(value.children[1].children[2].children.length == 0); 1997 } 1998 1999 with(parse!(defs!(), ParserKind!(true, true))(q{@setSkip($) int hoge = $; @setSkip($) int piyo = $;})) 2000 { 2001 assert(match == true); 2002 assert(nextInput.source == ""); 2003 assert(value.token.type == TokenType.DEFINITIONS); 2004 assert(value.children.length == 2); 2005 assert(value.children[0].token.type == TokenType.DEFINITION); 2006 assert(value.children[0].children.length == 3); 2007 assert(value.children[0].children[0].token.type == TokenType.TEMPLATE_INSTANCE); 2008 assert(value.children[0].children[0].token.text == "int"); 2009 assert(value.children[0].children[0].children.length == 0); 2010 assert(value.children[0].children[1].token.type == TokenType.ID); 2011 assert(value.children[0].children[1].token.text == "hoge"); 2012 assert(value.children[0].children[1].children.length == 0); 2013 assert(value.children[0].children[2].token.type == TokenType.SET_SKIP); 2014 assert(value.children[0].children[2].children.length == 2); 2015 assert(value.children[0].children[2].children[0].token.type == TokenType.DOLLAR); 2016 assert(value.children[0].children[2].children[0].token.text == "$"); 2017 assert(value.children[0].children[2].children[0].children.length == 0); 2018 assert(value.children[0].children[2].children[1].token.type == TokenType.DOLLAR); 2019 assert(value.children[0].children[2].children[1].token.text == "$"); 2020 assert(value.children[0].children[2].children[1].children.length == 0); 2021 assert(value.children[1].token.type == TokenType.DEFINITION); 2022 assert(value.children[1].children.length == 3); 2023 assert(value.children[1].children[0].token.type == TokenType.TEMPLATE_INSTANCE); 2024 assert(value.children[1].children[0].token.text == "int"); 2025 assert(value.children[1].children[0].children.length == 0); 2026 assert(value.children[1].children[1].token.type == TokenType.ID); 2027 assert(value.children[1].children[1].token.text == "piyo"); 2028 assert(value.children[1].children[1].children.length == 0); 2029 assert(value.children[1].children[2].token.type == TokenType.SET_SKIP); 2030 assert(value.children[1].children[2].children.length == 2); 2031 assert(value.children[1].children[2].children[0].token.type == TokenType.DOLLAR); 2032 assert(value.children[1].children[2].children[0].token.text == "$"); 2033 assert(value.children[1].children[2].children[0].children.length == 0); 2034 assert(value.children[1].children[2].children[1].token.type == TokenType.DOLLAR); 2035 assert(value.children[1].children[2].children[1].token.text == "$"); 2036 assert(value.children[1].children[2].children[1].children.length == 0); 2037 } 2038 2039 with(parse!(defs!(), ParserKind!(true, true))(q{@_setSkip($) @setSkip($) int hoge = $; @setSkip($) int piyo = $;})) 2040 { 2041 assert(match == true); 2042 assert(nextInput.source == ""); 2043 assert(value.token.type == TokenType.DEFINITIONS); 2044 assert(value.children.length == 3); 2045 assert(value.children[0].token.type == TokenType.GLOBAL_SET_SKIP); 2046 assert(value.children[0].children.length == 1); 2047 assert(value.children[0].children[0].token.type == TokenType.DOLLAR); 2048 assert(value.children[0].children[0].token.text == "$"); 2049 assert(value.children[0].children[0].children.length == 0); 2050 assert(value.children[1].token.type == TokenType.DEFINITION); 2051 assert(value.children[1].children.length == 3); 2052 assert(value.children[1].children[0].token.type == TokenType.TEMPLATE_INSTANCE); 2053 assert(value.children[1].children[0].token.text == "int"); 2054 assert(value.children[1].children[0].children.length == 0); 2055 assert(value.children[1].children[1].token.type == TokenType.ID); 2056 assert(value.children[1].children[1].token.text == "hoge"); 2057 assert(value.children[1].children[1].children.length == 0); 2058 assert(value.children[1].children[2].token.type == TokenType.SET_SKIP); 2059 assert(value.children[1].children[2].children.length == 2); 2060 assert(value.children[1].children[2].children[0].token.type == TokenType.DOLLAR); 2061 assert(value.children[1].children[2].children[0].token.text == "$"); 2062 assert(value.children[1].children[2].children[0].children.length == 0); 2063 assert(value.children[1].children[2].children[1].token.type == TokenType.DOLLAR); 2064 assert(value.children[1].children[2].children[1].token.text == "$"); 2065 assert(value.children[1].children[2].children[1].children.length == 0); 2066 assert(value.children[2].token.type == TokenType.DEFINITION); 2067 assert(value.children[2].children.length == 3); 2068 assert(value.children[2].children[0].token.type == TokenType.TEMPLATE_INSTANCE); 2069 assert(value.children[2].children[0].token.text == "int"); 2070 assert(value.children[2].children[0].children.length == 0); 2071 assert(value.children[2].children[1].token.type == TokenType.ID); 2072 assert(value.children[2].children[1].token.text == "piyo"); 2073 assert(value.children[2].children[1].children.length == 0); 2074 assert(value.children[2].children[2].token.type == TokenType.SET_SKIP); 2075 assert(value.children[2].children[2].children.length == 2); 2076 assert(value.children[2].children[2].children[0].token.type == TokenType.DOLLAR); 2077 assert(value.children[2].children[2].children[0].token.text == "$"); 2078 assert(value.children[2].children[2].children[0].children.length == 0); 2079 assert(value.children[2].children[2].children[1].token.type == TokenType.DOLLAR); 2080 assert(value.children[2].children[2].children[1].token.text == "$"); 2081 assert(value.children[2].children[2].children[1].children.length == 0); 2082 } 2083 }