1 module ctpg.combinators;
2 
3 import std.conv : to;
4 import std.typecons  : Tuple, tuple;
5 import std.traits : CommonType, isArray;
6 import std.range : hasSlicing;
7 
8 import ctpg : parse;
9 
10 import ctpg.for_unittest;
11 import ctpg.parse_result : ParseResult, getParseResultType, getParseResultTypes;
12 import ctpg.parser_kind  : ParserKind, ParserKinds;
13 import ctpg.input        : Input;
14 import ctpg.caller       : Caller;
15 import ctpg.none         : None;
16 import ctpg.macro_       : MAKE_RESULT;
17 import ctpg.option       : Option;
18 import ctpg.is_wrapper   : isSameType;
19 
20 import parsers = ctpg.parsers;
21 
22 import compile_time_unittest : enableCompileTimeUnittest;
23 mixin enableCompileTimeUnittest;
24 
25 import selflinoin : makeCompilationErrorMessage;
26 
27 
28 template untuple(alias parser)
29 {
30     template build(alias kind, SrcType)
31     {
32         static if(kind.hasValue)
33         {
34             static if(getParseResultType!(parser.build!(kind, SrcType)).length == 1)
35             {
36                 mixin MAKE_RESULT!q{ getParseResultType!(parser.build!(kind, SrcType)).Types[0] };
37 
38                 Result parse(Input!SrcType input, in Caller caller)
39                 {
40                     Result result;
41 
42                     with(parser.build!(kind, SrcType).parse(input, caller))
43                     {
44                         static if(kind.hasError)
45                         {
46                             result.error = error;
47                         }
48 
49                         if(match)
50                         {
51                             result.match = true;
52                             result.nextInput = nextInput;
53                             result.value = value[0];
54                         }
55                     }
56 
57                     return result;
58                 }
59             }
60             else
61             {
62                 alias parse = parser.build!(kind, SrcType).parse;
63             }
64         }
65         else
66         {
67             alias parse = parser.build!(kind, SrcType).parse;
68         }
69     }
70 }
71 
72 debug(ctpg) unittest
73 {
74     foreach(conv; convs) foreach(kind; ParserKinds)
75     {
76         with(parse!(untuple!(TestParser!(tuple("hoge", "fuga"))), kind)(conv!"input"))
77         {
78                                      assert(match              == true);
79             static if(kind.hasValue) assert(value              == tuple("hoge", "fuga"));
80                                      assert(nextInput.source   == conv!"input");
81                                      assert(nextInput.position == 0);
82                                      assert(nextInput.line     == 0);
83         }
84 
85         with(parse!(untuple!(TestParser!(tuple("hoge"))), kind)(conv!"input"))
86         {
87                                      assert(match              == true);
88             static if(kind.hasValue) assert(value              == "hoge");
89                                      assert(nextInput.source   == conv!"input");
90                                      assert(nextInput.position == 0);
91                                      assert(nextInput.line     == 0);
92         }
93     }
94 }
95 
96 
97 template sequence(parsers...)
98 {
99     static assert(parsers.length > 0);
100 
101     template build(alias kind, SrcType)
102     {
103         static if(parsers.length == 1)
104         {
105             alias T = getParseResultType!(parsers[0].build!(kind, SrcType));
106 
107             static if(is(T == None)) mixin MAKE_RESULT!q{ Tuple!() };
108             else                     mixin MAKE_RESULT!q{ Tuple!T  };
109 
110             Result parse(Input!SrcType input, in Caller caller)
111             {
112                 Result result;
113 
114                 auto head = parsers[0].build!(kind, SrcType).parse(input, caller);
115 
116                 static if(kind.hasError)
117                 {
118                     result.error = head.error;
119                 }
120 
121                 if(!head.match)
122                 {
123                     return result;
124                 }
125 
126                 result.match     = true;
127                 result.nextInput = head.nextInput;
128 
129                 static if(kind.hasValue && !is(T == None))
130                 {
131                     result.value = tuple(head.value);
132                 }
133 
134                 return result;
135             }
136         }
137         else static if(parsers.length > 1)
138         {
139             alias T = getParseResultType!(parsers[0].build!(kind, SrcType));
140 
141             static if(is(T == None)) mixin MAKE_RESULT!q{           getParseResultType!(sequence!(parsers[1..$]).build!(kind, SrcType)) };
142             else                     mixin MAKE_RESULT!q{ Tuple!(T, getParseResultType!(sequence!(parsers[1..$]).build!(kind, SrcType)).Types) };
143 
144             Result parse(Input!SrcType input, in Caller caller)
145             {
146                 Result result;
147 
148                 auto head = parsers[0].build!(kind, SrcType).parse(input, caller);
149 
150                 static if(kind.hasError)
151                 {
152                     result.error = head.error;
153                 }
154 
155                 if(!head.match)
156                 {
157                     return result;
158                 }
159 
160                 auto tail = sequence!(parsers[1..$]).build!(kind, SrcType).parse(head.nextInput, caller);
161 
162                 static if(kind.hasError)
163                 {
164                     if(result.error.position <=  tail.error.position)
165                     {
166                         result.error = tail.error;
167                     }
168                 }
169 
170                 if(!tail.match)
171                 {
172                     return result;
173                 }
174 
175                 result.match = true;
176                 result.nextInput = tail.nextInput;
177 
178                 static if(kind.hasValue)
179                 {
180                     static if(is(T == None)) result.value =                   tail.value;
181                     else                     result.value = tuple(head.value, tail.value.field);
182                 }
183 
184                 return result;
185             }
186         }
187     }
188 }
189 
190 debug(ctpg) unittest
191 {
192     foreach(conv; convs) foreach(kind; ParserKinds)
193     {
194         with(parse!(sequence!(parsers.string_!"hoge", parsers.string_!"fuga"), kind)(conv!"hogefugahoge"))
195         {
196                                      assert(match              == true);
197             static if(kind.hasValue) assert(value              == tuple("hoge", "fuga"));
198                                      assert(nextInput.source   == conv!"hoge");
199                                      assert(nextInput.position == 8);
200                                      assert(nextInput.line     == 0);
201         }
202 
203         with(parse!(sequence!(parsers.string_!"hoge", parsers.string_!"fuga"), kind)(conv!"hoge"))
204         {
205                                      assert(match          == false);
206             static if(kind.hasError) assert(error.msg      == "'fuga' expected");
207             static if(kind.hasError) assert(error.position == 4);
208         }
209 
210         with(parse!(sequence!(parsers.string_!"hoge", parsers.string_!"fuga"), kind)(conv!"fuga"))
211         {
212                                      assert(match          == false);
213             static if(kind.hasError) assert(error.msg      == "'hoge' expected");
214             static if(kind.hasError) assert(error.position == 0);
215         }
216 
217         with(parse!(sequence!(parsers.string_!"hoge", TestParser!(None()), parsers.string_!"fuga"), kind)(conv!"hogefuga"))
218         {
219                                      assert(match              == true);
220             static if(kind.hasValue) assert(value              == tuple("hoge", "fuga"));
221                                      assert(nextInput.source   == conv!"");
222                                      assert(nextInput.position == 8);
223                                      assert(nextInput.line     == 0);
224         }
225     }
226 }
227 
228 
229 
230 template choiceWithFileLine(string file, size_t line, parsers...)
231 {
232     static assert(parsers.length > 0);
233 
234     template build(alias kind, SrcType)
235     {
236         static if (kind.hasValue && isSameType!(CommonType!(getParseResultTypes!(kind, SrcType, parsers)), void))
237         {
238             pragma(msg, makeCompilationErrorMessage("incompatible types: " ~ getParseResultTypes!(kind, SrcType, parsers).stringof, file, line));
239             static assert(false);
240         }
241 
242         static if(parsers.length == 1)
243         {
244             mixin MAKE_RESULT!q{ getParseResultType!(parsers[0].build!(kind, SrcType)) };
245 
246             Result parse(Input!SrcType input, in Caller caller)
247             {
248                 Result result;
249 
250                 auto head = parsers[0].build!(kind, SrcType).parse(input, caller);
251 
252                 static if(kind.hasError)
253                 {
254                     result.error = head.error;
255                 }
256 
257                 if(head.match)
258                 {
259                     result.match = true;
260                     result.nextInput = head.nextInput;
261 
262                     static if(kind.hasValue)
263                     {
264                         result.value = head.value;
265                     }
266                 }
267 
268                 return result;
269             }
270         }
271         else static if(parsers.length > 1)
272         {
273             mixin MAKE_RESULT!q{ CommonType!(getParseResultType!(parsers[0].build!(kind, SrcType)), getParseResultType!(choice!(parsers[1..$]).build!(kind, SrcType))) };
274 
275             Result parse(Input!SrcType input, in Caller caller)
276             {
277                 Result result;
278 
279                 auto head = parsers[0].build!(kind, SrcType).parse(input.save, caller);
280 
281                 static if(kind.hasError)
282                 {
283                     result.error = head.error;
284                 }
285 
286                 if(head.match)
287                 {
288                     result.match = true;
289                     result.nextInput = head.nextInput;
290 
291                     static if(kind.hasValue)
292                     {
293                         result.value = head.value;
294                     }
295 
296                     return result;
297                 }
298 
299                 auto tail = choice!(parsers[1..$]).build!(kind, SrcType).parse(input, caller);
300 
301                 static if(kind.hasError)
302                 {
303                     if(result.error.position <= tail.error.position)
304                     {
305                         result.error = tail.error;
306                     }
307                 }
308 
309                 if(tail.match)
310                 {
311                     result.match = true;
312                     result.nextInput = tail.nextInput;
313 
314                     static if(kind.hasValue)
315                     {
316                         result.value = tail.value;
317                     }
318                 }
319 
320                 return result;
321             }
322         }
323     }
324 }
325 
326 template choice(parsers...)
327 {
328     alias choice = choiceWithFileLine!("", 0, parsers);
329 }
330 
331 debug(ctpg) unittest
332 {
333     foreach(conv; convs) foreach(kind; ParserKinds)
334     {
335         with(parse!(choice!(parsers.string_!"hoge", parsers.string_!"fuga"), kind)(conv!"hoge"))
336         {
337                                      assert(match              == true);
338             static if(kind.hasValue) assert(value              == "hoge");
339                                      assert(nextInput.source   == conv!"");
340                                      assert(nextInput.position == 4);
341                                      assert(nextInput.line     == 0);
342         }
343 
344         with(parse!(choice!(parsers.string_!"hoge", parsers.string_!"fuga"), kind)(conv!"fuga"))
345         {
346                                      assert(match              == true);
347             static if(kind.hasValue) assert(value              == "fuga");
348                                      assert(nextInput.source   == conv!"");
349                                      assert(nextInput.position == 4);
350                                      assert(nextInput.line     == 0);
351         }
352 
353         with(parse!(choice!(parsers.string_!"hoge", parsers.string_!"fuga"), kind)(conv!"piyo"))
354         {
355                                      assert(match          == false);
356             static if(kind.hasError) assert(error.msg      == "'fuga' expected");
357             static if(kind.hasError) assert(error.position == 0);
358         }
359 
360         with(parse!(choice!(sequence!(parsers.string_!"hoge", parsers.string_!"piyo"), parsers.string_!"fuga"), ParserKind!(false, kind.hasError))(conv!"hoge"))
361         {
362                                      assert(match          == false);
363             static if(kind.hasError) assert(error.msg      == "'piyo' expected");
364             static if(kind.hasError) assert(error.position == 4);
365         }
366 
367         debug(ctpgCompilesTest)
368         {
369             static if(kind.hasValue)
370             {
371                 static assert(!__traits(compiles, parse!(choice!(TestParser!"hoge", TestParser!1), kind)(conv!"")));
372             }
373             else
374             {
375                 static assert(__traits(compiles, parse!(choice!(TestParser!"hoge", TestParser!1), kind)(conv!"")));
376             }
377         }
378     }
379 }
380 
381 
382 template more(size_t n, alias parser, alias sep = success!())
383 {
384     template build(alias kind, SrcType)
385     {
386         mixin MAKE_RESULT!q{ getParseResultType!(parser.build!(kind, SrcType))[] };
387 
388         Result parse(Input!SrcType input, in Caller caller)
389         {
390             Result result;
391             size_t size = 1;
392             Input!SrcType next = input.save;
393 
394             auto head = parser.build!(kind, SrcType).parse(next, caller);
395 
396             static if(kind.hasError)
397             {
398                 result.error = head.error;
399             }
400 
401             if(!head.match)
402             {
403                 if(n == 0)
404                 {
405                     result.match = true;
406                     result.nextInput = input;
407                 }
408 
409                 return result;
410             }
411 
412             static if(kind.hasValue)
413             {
414                 result.value ~= head.value;
415             }
416 
417             next = head.nextInput.save;
418 
419             while(true)
420             {
421                 auto r1 = sep.build!(ParserKind!(false, kind.hasError), SrcType).parse(next, caller);
422 
423                 static if(kind.hasError)
424                 {
425                     if(result.error.position <= r1.error.position)
426                     {
427                         result.error = r1.error;
428                     }
429                 }
430 
431                 if(r1.match)
432                 {
433                     auto r2 = parser.build!(kind, SrcType).parse(r1.nextInput, caller);
434 
435                     static if(kind.hasError)
436                     {
437                         if(result.error.position <= r2.error.position)
438                         {
439                             result.error = r2.error;
440                         }
441                     }
442 
443                     if(r2.match)
444                     {
445                         static if(kind.hasValue)
446                         {
447                             result.value ~= r2.value;
448                         }
449 
450                         ++size;
451                         next = r2.nextInput;
452                     } 
453                     else
454                     {
455                         if(size < n)
456                         {
457                             return result;
458                         }
459 
460                         break;
461                     }
462                 }
463                 else
464                 {
465                     if(size < n)
466                     {
467                         return result;
468                     }
469 
470                     break;
471                 }
472             }
473 
474             result.match = true;
475             result.nextInput = next;
476 
477             return result;
478         }
479     }
480 }
481 
482 template more0(alias parser, alias sep = parsers.success!())
483 {
484     alias more0 = more!(0, parser, sep);
485 }
486 
487 
488 template more1(alias parser, alias sep = parsers.success!())
489 {
490     alias more1 = more!(1, parser, sep);
491 }
492 
493 debug(ctpg) unittest
494 {
495     foreach(conv; convs) foreach(kind; ParserKinds)
496     {
497         with(parse!(more!(0, parsers.string_!"hoge", parsers.string_!","), kind)(conv!""))
498         {
499                                      assert(match              == true);
500             static if(kind.hasValue) assert(value              == []);
501                                      assert(nextInput.source   == conv!"");
502                                      assert(nextInput.position == 0);
503                                      assert(nextInput.line     == 0);
504         }
505 
506         with(parse!(more!(0, parsers.string_!"hoge", parsers.string_!","), kind)(conv!"hoge,hoge,hoge"))
507         {
508                                      assert(match              == true);
509             static if(kind.hasValue) assert(value              == ["hoge", "hoge", "hoge"]);
510                                      assert(nextInput.source   == conv!"");
511                                      assert(nextInput.position == 14);
512                                      assert(nextInput.line     == 0);
513         }
514 
515         with(parse!(more!(0, parsers.string_!"hoge", parsers.string_!","), kind)(conv!"hoge,hoge,hoge,"))
516         {
517                                      assert(match              == true);
518             static if(kind.hasValue) assert(value              == ["hoge", "hoge", "hoge"]);
519                                      assert(nextInput.source   == conv!",");
520                                      assert(nextInput.position == 14);
521                                      assert(nextInput.line     == 0);
522         }
523 
524         with(parse!(more!(4, parsers.string_!"hoge", parsers.string_!","), kind)(conv!"hoge,hoge,hoge"))
525         {
526                                      assert(match          == false);
527             static if(kind.hasError) assert(error.msg      == "',' expected");
528             static if(kind.hasError) assert(error.position == 14);
529         }
530 
531         with(parse!(more!(4, parsers.string_!"hoge", parsers.string_!","), kind)(conv!"hoge,hoge,hoge,"))
532         {
533                                      assert(match          == false);
534             static if(kind.hasError) assert(error.msg      == "'hoge' expected");
535             static if(kind.hasError) assert(error.position == 15);
536         }
537     }
538 }
539 
540 
541 template andPred(alias parser)
542 {
543     template build(alias kind, SrcType)
544     {
545         mixin MAKE_RESULT!q{ None };
546 
547         Result parse(Input!SrcType input, in Caller caller)
548         {
549             Result result;
550             result.nextInput = input;
551 
552             with(parser.build!(ParserKind!(false, kind.hasError), SrcType).parse(input.save, caller))
553             {
554                 static if(kind.hasError)
555                 {
556                     result.error = error;
557                 }
558 
559                 result.match = match;
560             }
561 
562             return result;
563         }
564     }
565 }
566 
567 debug(ctpg) unittest
568 {
569     foreach(conv; convs) foreach(kind; ParserKinds)
570     {
571         with(parse!(andPred!(parsers.string_!"hoge"), kind)(conv!"hoge"))
572         {
573                                      assert(match              == true);
574             static if(kind.hasValue) assert(value              == None());
575                                      assert(nextInput.source   == conv!"hoge");
576                                      assert(nextInput.position == 0);
577                                      assert(nextInput.line     == 0);
578         }
579 
580         with(parse!(andPred!(parsers.string_!"hoge"), kind)(conv!"fuga"))
581         {
582                                      assert(match          == false);
583             static if(kind.hasError) assert(error.msg      == "'hoge' expected");
584             static if(kind.hasError) assert(error.position == 0);
585         }
586     }
587 }
588 
589 
590 template notPred(alias parser)
591 {
592     template build(alias kind, SrcType)
593     {
594         mixin MAKE_RESULT!q{ None };
595 
596         Result parse(Input!SrcType input, in Caller caller)
597         {
598             Result result;
599             result.nextInput = input;
600 
601             with(parser.build!(ParserKind!(false, false), SrcType).parse(input.save, caller))
602             {
603                 static if(kind.hasError)
604                 {
605                     result.error.msg = "failure expected";
606                     result.error.position = input.position;
607                 }
608 
609                 result.match = !match;
610             }
611 
612             return result;
613         }
614     }
615 }
616 
617 debug(ctpg) unittest
618 {
619     foreach(conv; convs) foreach(kind; ParserKinds)
620     {
621         with(parse!(notPred!(parsers.string_!"hoge"), kind)(conv!"fuga"))
622         {
623                                      assert(match              == true);
624             static if(kind.hasValue) assert(value              == None());
625                                      assert(nextInput.source   == conv!"fuga");
626                                      assert(nextInput.position == 0);
627                                      assert(nextInput.line     == 0);
628         }
629 
630         with(parse!(notPred!(parsers.string_!"hoge"), kind)(conv!"hoge"))
631         {
632                                      assert(match          == false);
633             static if(kind.hasError) assert(error.msg      == "failure expected");
634             static if(kind.hasError) assert(error.position == 0);
635         }
636     }
637 }
638 
639 
640 template option(alias parser)
641 {
642     template build(alias kind, SrcType)
643     {
644         mixin MAKE_RESULT!q{ Option!(getParseResultType!(parser.build!(kind, SrcType))) };
645 
646         Result parse(Input!SrcType input, in Caller caller)
647         {
648             Result result;
649             result.match = true;
650 
651             with(parser.build!(kind, SrcType).parse(input.save, caller))
652             {
653                 static if(kind.hasError)
654                 {
655                     result.error = error;
656                 }
657 
658                 if(match)
659                 {
660                     result.nextInput = nextInput;
661 
662                     static if(kind.hasValue)
663                     {
664                         result.value.value = value;
665                         result.value.some = true;
666                     }
667                 }
668                 else
669                 {
670                     result.nextInput = input;
671                 }
672             }
673 
674             return result;
675         }
676     }
677 }
678 
679 debug(ctpg) unittest
680 {
681     foreach(conv; convs) foreach(kind; ParserKinds)
682     {
683         with(parse!(option!(parsers.string_!"hoge"), kind)(conv!"fuga"))
684         {
685                                      assert(match              == true);
686             static if(kind.hasValue) assert(value.some         == false);
687                                      assert(nextInput.source   == conv!"fuga");
688                                      assert(nextInput.position == 0);
689                                      assert(nextInput.line     == 0);
690         }
691 
692         with(parse!(option!(parsers.string_!"hoge"), kind)(conv!"hoge"))
693         {
694                                      assert(match              == true);
695             static if(kind.hasValue) assert(value.some         == true);
696             static if(kind.hasValue) assert(value              == "hoge");
697                                      assert(nextInput.source   == conv!"");
698                                      assert(nextInput.position == 4);
699                                      assert(nextInput.line     == 0);
700         }
701     }
702 }
703 
704 
705 template none(alias parser)
706 {
707     template build(alias kind, SrcType)
708     {
709         static if(kind.hasValue)
710         {
711             alias Result = ParseResult!(kind, SrcType, None);
712 
713             Result parse(Input!SrcType input, in Caller caller)
714             {
715                 Result result;
716 
717                 with(parser.build!(ParserKind!(false, kind.hasError), SrcType).parse(input, caller))
718                 {
719                     static if(kind.hasError)
720                     {
721                         result.error = error;
722                     }
723 
724                     result.match = match;
725 
726                     if(match)
727                     {
728                         result.nextInput = nextInput;
729                     }
730                 }
731 
732                 return result;
733             }
734         }
735         else
736         {
737             alias parse = parser.build!(kind, SrcType).parse;
738         }
739     }
740 }
741 
742 debug(ctpg) unittest
743 {
744     foreach(conv; convs) foreach(kind; ParserKinds)
745     {
746         with(parse!(none!(parsers.string_!"hoge"), kind)(conv!"hoge"))
747         {
748                                      assert(match              == true);
749             static if(kind.hasValue) assert(value              == None());
750                                      assert(nextInput.source   == conv!"");
751                                      assert(nextInput.position == 4);
752                                      assert(nextInput.line     == 0);
753         }
754 
755         with(parse!(none!(parsers.string_!"hoge"), kind)(conv!"fuga"))
756         {
757                                      assert(match          == false);
758             static if(kind.hasError) assert(error.msg      == "'hoge' expected");
759             static if(kind.hasError) assert(error.position == 0);
760         }
761     }
762 }
763 
764 
765 template convert(alias parser, alias converter, size_t line = 0, string file = "")
766 {
767     template build(alias kind, SrcType)
768     {
769         static if(kind.hasValue)
770         {
771             alias T = getParseResultType!(parser.build!(kind, SrcType));
772 
773                  static if(is(converter == class ) && __traits(compiles, new converter(T.init.field))) alias ConverterType = converter;
774             else static if(is(converter == class ) && __traits(compiles, new converter(T.init      ))) alias ConverterType = converter;
775             else static if(is(converter == struct) && __traits(compiles,     converter(T.init.field))) alias ConverterType = converter;
776             else static if(is(converter == struct) && __traits(compiles,     converter(T.init      ))) alias ConverterType = converter;
777             else static if(                           __traits(compiles,     converter(T.init.field))) alias ConverterType = typeof(converter(T.init.field));
778             else static if(                           __traits(compiles,     converter(T.init      ))) alias ConverterType = typeof(converter(T.init      ));
779             else                                                                                       alias ConverterType = void;
780 
781             static if(is(ConverterType == void))
782             {
783                 pragma(msg, makeCompilationErrorMessage("Cannot call '" ~ converter.stringof ~ "' using '>>' with types: " ~ T.stringof, file, line));
784                 static assert(false);
785             }
786 
787             mixin MAKE_RESULT!q{ ConverterType };
788 
789             static Result parse(Input!SrcType input, in Caller caller)
790             {
791                 Result result;
792 
793                 with(parser.build!(kind, SrcType).parse(input, caller))
794                 {
795                     static if(kind.hasError)
796                     {
797                         result.error = error;
798                     }
799 
800                     if(match)
801                     {
802                         result.match = true;
803                         result.nextInput = nextInput;
804 
805                         static if(kind.hasValue)
806                         {
807                                  static if(is(converter == class ) && __traits(compiles, new converter(T.init.field))) result.value = new converter(value.field);
808                             else static if(is(converter == class ) && __traits(compiles, new converter(T.init      ))) result.value = new converter(value      );
809                             else static if(                           __traits(compiles,     converter(T.init.field))) result.value =     converter(value.field);
810                             else static if(                           __traits(compiles,     converter(T.init      ))) result.value =     converter(value      );
811                         }
812                     }
813                 }
814 
815                 return result;
816             }
817         }
818         else
819         {
820             alias parse = parser.build!(kind, SrcType).parse;
821         }
822     }
823 }
824 
825 debug(ctpg) unittest
826 {
827     static struct Struct
828     {
829         size_t len;
830 
831         this(string str)
832         {
833             len = str.length;
834         }
835     }
836 
837     static class Class
838     {
839         size_t len;
840 
841         this(string str)
842         {
843             len = str.length;
844         }
845     }
846     
847     
848     static size_t Function(string str)
849     {
850         return str.length;
851     }
852 
853     static size_t TemplateFunction(T)(T str)
854     {
855         return str.length;
856     }
857 
858     foreach(conv; convs) foreach(kind; ParserKinds)
859     {
860         with(parse!(convert!(parsers.string_!"hoge", Struct), kind)(conv!"hogee"))
861         {
862                                      assert(match              == true);
863             static if(kind.hasValue) assert(value.len          == 4);
864                                      assert(nextInput.source   == conv!"e");
865                                      assert(nextInput.position == 4);
866                                      assert(nextInput.line     == 0);
867         }
868 
869         with(parse!(convert!(parsers.string_!"hoge", Struct), kind)(conv!"!!!!"))
870         {
871                                      assert(match          == false);
872             static if(kind.hasError) assert(error.msg      == "'hoge' expected");
873             static if(kind.hasError) assert(error.position == 0);
874         }
875 
876         with(parse!(convert!(parsers.string_!"hoge", Class), kind)(conv!"hogee"))
877         {
878                                      assert(match              == true);
879             static if(kind.hasValue) assert(value.len          == 4);
880                                      assert(nextInput.source   == conv!"e");
881                                      assert(nextInput.position == 4);
882                                      assert(nextInput.line     == 0);
883         }
884 
885         with(parse!(convert!(parsers.string_!"hoge", Class), kind)(conv!"!!!!"))
886         {
887                                      assert(match          == false);
888             static if(kind.hasError) assert(error.msg      == "'hoge' expected");
889             static if(kind.hasError) assert(error.position == 0);
890         }
891 
892         with(parse!(convert!(parsers.string_!"hoge", Function), kind)(conv!"hogee"))
893         {
894                                      assert(match              == true);
895             static if(kind.hasValue) assert(value              == 4);
896                                      assert(nextInput.source   == conv!"e");
897                                      assert(nextInput.position == 4);
898                                      assert(nextInput.line     == 0);
899         }
900 
901         with(parse!(convert!(parsers.string_!"hoge", Function), kind)(conv!"!!!!"))
902         {
903                                      assert(match          == false);
904             static if(kind.hasError) assert(error.msg      == "'hoge' expected");
905             static if(kind.hasError) assert(error.position == 0);
906         }
907 
908         with(parse!(convert!(parsers.string_!"hoge", TemplateFunction), kind)(conv!"hogee"))
909         {
910                                      assert(match              == true);
911             static if(kind.hasValue) assert(value              == 4);
912                                      assert(nextInput.source   == conv!"e");
913                                      assert(nextInput.position == 4);
914                                      assert(nextInput.line     == 0);
915         }
916 
917         with(parse!(convert!(parsers.string_!"hoge", TemplateFunction), kind)(conv!"!!!!"))
918         {
919                                      assert(match          == false);
920             static if(kind.hasError) assert(error.msg      == "'hoge' expected");
921             static if(kind.hasError) assert(error.position == 0);
922         }
923 
924         with(parse!(convert!(parsers.string_!"hoge", (x) => x.length), kind)(conv!"hogee"))
925         {
926                                      assert(match              == true);
927             static if(kind.hasValue) assert(value              == 4);
928                                      assert(nextInput.source   == conv!"e");
929                                      assert(nextInput.position == 4);
930                                      assert(nextInput.line     == 0);
931         }
932 
933         with(parse!(convert!(parsers.string_!"hoge", (x) => x.length), kind)(conv!"!!!!"))
934         {
935                                      assert(match          == false);
936             static if(kind.hasError) assert(error.msg      == "'hoge' expected");
937             static if(kind.hasError) assert(error.position == 0);
938         }
939 
940         with(parse!(convert!(parsers.string_!"hoge", (x){ return x.length; }), kind)(conv!"hogee"))
941         {
942                                      assert(match              == true);
943             static if(kind.hasValue) assert(value              == 4);
944                                      assert(nextInput.source   == conv!"e");
945                                      assert(nextInput.position == 4);
946                                      assert(nextInput.line     == 0);
947         }
948 
949         with(parse!(convert!(parsers.string_!"hoge", (x){ return x.length; }), kind)(conv!"!!!!"))
950         {
951                                      assert(match          == false);
952             static if(kind.hasError) assert(error.msg      == "'hoge' expected");
953             static if(kind.hasError) assert(error.position == 0);
954         }
955 
956         debug(ctpgCompilesTest)
957         {
958             static if(kind.hasValue)
959             {
960                 static assert(!__traits(compiles, parse!(convert!(parsers.string_!"hoge", (size_t x){ return x; }), kind)(conv!"hoge")));
961             }
962             else
963             {
964                 static assert(__traits(compiles, parse!(convert!(parsers.string_!"hoge", (size_t x){ return x; }), kind)(conv!"hoge")));
965             }
966         }
967     }
968 }
969 
970 
971 template check(alias parser, alias checker, size_t line = 0, string file = "")
972 {
973     template build(alias kind, SrcType)
974     {
975         alias T = getParseResultType!(parser.build!(ParserKind!(true, kind.hasError), SrcType));
976 
977         static if(!__traits(compiles, checker(T.init.field)) && !__traits(compiles, checker(T.init)))
978         {
979             pragma(msg, makeCompilationErrorMessage("Cannot call '" ~ checker.stringof ~ "' using '>?' with types: " ~ T.stringof, file, line));
980             static assert(false);
981         }
982         else static if(!is(typeof(checker(T.init.field)) == bool) && !is(typeof(checker(T.init)) == bool))
983         {
984             pragma(msg, makeCompilationErrorMessage("'" ~ checker.stringof ~ "' does not return bool", file, line));
985             static assert(false);
986         }
987 
988         mixin MAKE_RESULT!q{ T };
989 
990         Result parse(Input!SrcType input, in Caller caller)
991         {
992             Result result;
993 
994             with(parser.build!(ParserKind!(true, kind.hasError), SrcType).parse(input, caller))
995             {
996                 static if(kind.hasError)
997                 {
998                     result.error = error;
999                 }
1000 
1001                 if(match)
1002                 {
1003                          static if(is(typeof(checker(T.init.field)) == bool)) result.match = checker(value.field);
1004                     else static if(is(typeof(checker(T.init      )) == bool)) result.match = checker(value      );
1005 
1006                     if(result.match)
1007                     {
1008                         result.nextInput = nextInput;
1009 
1010                         static if(kind.hasValue)
1011                         {
1012                             result.value = value;
1013                         }
1014                     }
1015                     else
1016                     {
1017                         static if(kind.hasError)
1018                         {
1019                             result.error.msg = "passing check expected";
1020                             result.error.position = input.position;
1021                         }
1022                     }
1023                 }
1024             }
1025 
1026             return result;
1027         }
1028     }
1029 }
1030 
1031 debug(ctpg) unittest
1032 {
1033     static bool Function(string str)
1034     {
1035         return str.length == 4;
1036     }
1037 
1038     foreach(conv; convs) foreach(kind; ParserKinds)
1039     {
1040         with(parse!(check!(parsers.string_!"hoge", Function), kind)(conv!"hoge!"))
1041         {
1042                                      assert(match              == true);
1043             static if(kind.hasValue) assert(value              == "hoge");
1044                                      assert(nextInput.source   == conv!"!");
1045                                      assert(nextInput.position == 4);
1046                                      assert(nextInput.line     == 0);
1047         }
1048 
1049         with(parse!(check!(parsers.string_!"hoge!", Function), kind)(conv!"hoge!"))
1050         {
1051                                      assert(match          == false);
1052             static if(kind.hasError) assert(error.msg      == "passing check expected");
1053             static if(kind.hasError) assert(error.position == 0);
1054         }
1055 
1056         with(parse!(check!(parsers.string_!"hoge", Function), kind)(conv!"fuga"))
1057         {
1058                                      assert(match          == false);
1059             static if(kind.hasError) assert(error.msg      == "'hoge' expected");
1060             static if(kind.hasError) assert(error.position == 0);
1061         }
1062 
1063         debug(ctpgCompilesTest)
1064         {
1065             static assert(!__traits(compiles, parse!(check!(parsers.string_!"hoge", (int    i  ){ return false; }), kind)(conv!"hoge")));
1066             static assert(!__traits(compiles, parse!(check!(parsers.string_!"hoge", (string str){ return 0;     }), kind)(conv!"hoge")));
1067         }
1068     }
1069 }
1070 
1071 
1072 template inputSlice(alias parser, size_t line = 0, string file = "")
1073 {
1074     template build(alias kind, SrcType)
1075     {
1076         static if(kind.hasValue)
1077         {
1078             static if(!isArray!SrcType && !hasSlicing!SrcType)
1079             {
1080                 pragma(msg, makeCompilationErrorMessage("Input type should be sliceable", file, line));
1081                 static assert(false);
1082             }
1083 
1084             alias Result = ParseResult!(kind, SrcType, SrcType);
1085 
1086             Result parse(Input!SrcType input, in Caller caller)
1087             {
1088                 Result result;
1089 
1090                 with(parser.build!(ParserKind!(false, kind.hasError), SrcType).parse(input.save, caller))
1091                 {
1092                     static if(kind.hasError)
1093                     {
1094                         result.error = error;
1095                     }
1096 
1097                     if(match)
1098                     {
1099                         result.match = true;
1100                         result.nextInput = nextInput;
1101 
1102                         static if(kind.hasValue)
1103                         {
1104                             result.value = input.source[0 .. nextInput.position - input.position];
1105                         }
1106                     }
1107                 }
1108 
1109                 return result;
1110             }
1111         }
1112         else
1113         {
1114             alias parse = parser.build!(kind, SrcType).parse;
1115         }
1116     }
1117 }
1118 
1119 debug(ctpg) unittest
1120 {
1121     foreach(conv; convs) foreach(kind; ParserKinds)
1122     {
1123         with(parse!(inputSlice!(sequence!(parsers.string_!"hoge", parsers.string_!"fuga")), kind)(conv!"hogefugapiyo"))
1124         {
1125                                      assert(match              == true);
1126             static if(kind.hasValue) assert(value              == conv!"hogefuga");
1127                                      assert(nextInput.source   == conv!"piyo");
1128                                      assert(nextInput.position == 8);
1129                                      assert(nextInput.line     == 0);
1130         }
1131 
1132         debug(ctpgCompilesTest)
1133         {
1134             import std.algorithm : filter;
1135 
1136             static if(kind.hasValue)
1137             {
1138                 static assert(!__traits(compiles, parse!(inputSlice!(parsers.string_!"hoge"), kind)(conv!"hoge".filter!"true"())));
1139             }
1140             else
1141             {
1142                 static assert(__traits(compiles, parse!(inputSlice!(parsers.string_!"hoge"), kind)(conv!"hoge".filter!"true"())));
1143             }
1144         }
1145     }
1146 }
1147 
1148 
1149 template memoize(alias parser)
1150 {
1151     template build(alias kind, SrcType)
1152     {
1153         mixin MAKE_RESULT!q{ getParseResultType!(parser.build!(kind, SrcType)) };
1154 
1155         Result parse(Input!SrcType input, in Caller caller)
1156         {
1157             if(!__ctfe)
1158             {
1159                 static typeof(return)[Input!SrcType] memo;
1160 
1161                 auto p = input in memo;
1162                 if(p)
1163                 {
1164                     return *p;
1165                 }
1166 
1167                 auto result = parser.build!(kind, SrcType).parse(input, caller);
1168                 memo[input] = result;
1169 
1170                 return result;
1171             }
1172             else
1173             {
1174                 return parser.build!(kind, SrcType).parse(input, caller);
1175             }
1176         }
1177     }
1178 }
1179 
1180 debug(ctpg) unittest
1181 {
1182     foreach(conv; convs) foreach(kind; ParserKinds)
1183     {
1184         with(parse!(memoize!(parsers.string_!"hoge"), kind)(conv!"hogehoge"))
1185         {
1186                                      assert(match              == true);
1187             static if(kind.hasValue) assert(value              == "hoge");
1188                                      assert(nextInput.source   == conv!"hoge");
1189                                      assert(nextInput.position == 4);
1190                                      assert(nextInput.line     == 0);
1191         }
1192 
1193         with(parse!(memoize!(parsers.string_!"hoge"), kind)(conv!"hogehoge"))
1194         {
1195                                      assert(match              == true);
1196             static if(kind.hasValue) assert(value              == "hoge");
1197                                      assert(nextInput.source   == conv!"hoge");
1198                                      assert(nextInput.position == 4);
1199                                      assert(nextInput.line     == 0);
1200         }
1201 
1202         with(parse!(memoize!(parsers.string_!"\n\nhoge"), kind)(conv!"\n\nhogehoge"))
1203         {
1204                                      assert(match              == true);
1205             static if(kind.hasValue) assert(value              == "\n\nhoge");
1206                                      assert(nextInput.source   == conv!"hoge");
1207                                      assert(nextInput.position == 6);
1208                                      assert(nextInput.line     == 2);
1209         }
1210 
1211         with(parse!(memoize!(parsers.string_!"\n\nhoge"), kind)(conv!"\n\nhogehoge"))
1212         {
1213                                      assert(match              == true);
1214             static if(kind.hasValue) assert(value              == "\n\nhoge");
1215                                      assert(nextInput.source   == conv!"hoge");
1216                                      assert(nextInput.position == 6);
1217                                      assert(nextInput.line     == 2);
1218         }
1219     }
1220 }
1221 
1222 
1223 template changeError(alias parser, string errorMsg)
1224 {
1225     template build(alias kind, SrcType)
1226     {
1227         static if(kind.hasError)
1228         {
1229             mixin MAKE_RESULT!q{ getParseResultType!(parser.build!(kind, SrcType)) };
1230 
1231             Result parse(Input!SrcType input, in Caller caller)
1232             {
1233                 Result result;
1234 
1235                 with(parser.build!(ParserKind!(kind.hasValue, false), SrcType).parse(input, caller))
1236                 {
1237                     if(!match)
1238                     {
1239                         result.error.msg      = errorMsg;
1240                         result.error.position = input.position;
1241                     }
1242 
1243                     result.match     = match;
1244                     result.nextInput = nextInput;
1245 
1246                     static if(kind.hasValue)
1247                     {
1248                         result.value = value;
1249                     }
1250                 }
1251 
1252                 return result;
1253             }
1254         }
1255         else
1256         {
1257             alias parse = parser.build!(kind, SrcType).parse;
1258         }
1259     }
1260 }
1261 
1262 debug(ctpg) unittest
1263 {
1264     foreach(conv; convs) foreach(kind; ParserKinds)
1265     {
1266         with(parse!(changeError!(parsers.string_!"hoge", "エラーだよ!!"), kind)(conv!"hoge"))
1267         {
1268             assert(match              == true);
1269             assert(nextInput.source   == conv!"");
1270             assert(nextInput.position == 4);
1271             assert(nextInput.line     == 0);
1272         }
1273 
1274         with(parse!(changeError!(parsers.string_!"hoge", "エラーだよ!!"), kind)(conv!"fuga"))
1275         {
1276                                      assert(match          == false);
1277             static if(kind.hasError) assert(error.msg      == "エラーだよ!!");
1278             static if(kind.hasError) assert(error.position == 0);
1279         }
1280 
1281         with(parse!(changeError!(sequence!(parsers.string_!"hoge", parsers.string_!"fuga"), "エラーだよ!!"), kind)(conv!"hoge"))
1282         {
1283                                      assert(match          == false);
1284             static if(kind.hasError) assert(error.msg      == "エラーだよ!!");
1285             static if(kind.hasError) assert(error.position == 0);
1286         }
1287     }
1288 }
1289 
1290 
1291 template skip(alias skip, alias parser)
1292 {
1293     template build(alias kind, SrcType)
1294     {
1295         mixin MAKE_RESULT!q{ getParseResultType!(parser.build!(kind, SrcType)) };
1296 
1297         Result parse(Input!SrcType input, in Caller caller)
1298         {
1299             auto skipped = skip.build!(ParserKind!(false, kind.hasError), SrcType).parse(input.save, caller);
1300 
1301             if(skipped.match)
1302             {
1303                 return parser.build!(kind, SrcType).parse(skipped.nextInput, caller);
1304             }
1305             else
1306             {
1307                 return parser.build!(kind, SrcType).parse(input, caller);
1308             }
1309         }
1310     }
1311 }
1312 
1313 debug(ctpg) unittest
1314 {
1315     foreach(conv; convs) foreach(kind; ParserKinds)
1316     {
1317         with(parse!(skip!(parsers.string_!"\n", parsers.string_!"hoge"), kind)(conv!"hogehoge"))
1318         {
1319                                      assert(match              == true);
1320             static if(kind.hasValue) assert(value              == "hoge");
1321                                      assert(nextInput.source   == conv!"hoge");
1322         }
1323 
1324         with(parse!(skip!(parsers.string_!"\n\n", parsers.string_!"hoge"), kind)(conv!"\n\nhogehoge"))
1325         {
1326                                      assert(match              == true);
1327             static if(kind.hasValue) assert(value              == "hoge");
1328                                      assert(nextInput.source   == conv!"hoge");
1329         }
1330     }
1331 }