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 }