1 module pry.combinators;
2 
3 import pry.traits;
4 import std.meta, std.range.primitives, std.typecons, std.traits;
5 
6 private:
7 
8 public struct Nullable(T){
9 	bool isNull = true;
10 	T value;
11 
12 	this(T val){
13 		value = val;
14 		isNull = false;
15 	}
16 
17 	void opAssign(T value){
18 		this.value = value;
19 		isNull = false;
20 	}
21 
22 	void nullify(){
23 		isNull = true;
24 		static if(is(T == struct))
25 			value.tupleof = T.init.tupleof;
26 		else
27 			value = T.init;
28 	}
29 
30 	alias value this;
31 }
32 
33 struct RepImpl(bool collect, Array, size_t minTimes, size_t maxTimes, Parser){
34 	alias Stream = ParserStream!Parser;
35 	static if(collect)
36 		alias Value = Array;
37 	else
38 		alias Value = Stream.Range;
39 	private Parser parser;
40 
41 	bool parse(ref Stream stream, ref Value value, ref Stream.Error err) const {
42 		auto start = stream.mark;
43 		ParserValue!Parser tmp;
44 		size_t i = 0;
45 		static if(collect) value = null;
46 		for(; i<minTimes; i++) {
47 			if(!parser.parse(stream, tmp, err)){
48 				stream.restore(start);
49 				return false;
50 			}
51 			static if(collect) value ~= tmp;
52 		}
53 		for(; i<maxTimes; i++){
54 			if(!parser.parse(stream, tmp, err)) break;
55 			static if(collect) value ~= tmp;
56 		}
57 		static if(!collect)
58 			value = stream.slice(start);
59 		return true;
60 	}
61 }
62 
63 
64 /// Apply parser for minTimes times or more and return consumed range.
65 public auto rep(size_t minTimes=1, size_t maxTimes=size_t.max, Parser)(Parser parser)
66 if(isParser!Parser){
67 	return RepImpl!(false, ParserValue!Parser[], minTimes, maxTimes, Parser)(parser);
68 }
69 
70 /// Apply parser for minTimes times or more and return array of results.
71 public auto array(size_t minTimes=1, size_t maxTimes=size_t.max, Parser)(Parser parser)
72 if(isParser!Parser){
73 	return RepImpl!(true, ParserValue!Parser[], minTimes, maxTimes, Parser)(parser);
74 }
75 
76 /// Apply parser for minTimes times or more and encode results to an UTF string.
77 public auto utfString(Char, size_t minTimes=1, size_t maxTimes=size_t.max, Parser)(Parser parser)
78 if(isParser!Parser){
79 	return RepImpl!(true, immutable(Char)[], minTimes, maxTimes, Parser)(parser);
80 }
81 
82 unittest
83 {
84 	import pry.atoms, pry.stream;
85 	alias S = SimpleStream!string;
86 	with(parsers!S)
87 	{
88 		auto p = tk!'a'.rep!2;
89 		string r;
90 		S.Error err;
91 		auto s = S("aaac");
92 		assert(p.parse(s, r, err));
93 		assert(r == "aaa");
94 		
95 		s = S("a");
96 		assert(!p.parse(s, r, err));
97 		assert(err.location == 1);
98 		assert(err.reason == "unexpected end of stream");
99 		
100 		auto p2 = range!('a', 'b').array;
101 		dchar[] r2;
102 		s = S("aba");
103 		assert(p2.parse(s, r2, err));
104 		assert(r2 == "aba"d);
105 		assert(s.empty);
106 
107 
108 		s = S("aaaa");
109 		auto p3 = tk!'a'.rep!(2,3);
110 		assert(p3.parse(s, r, err));
111 		assert(r == "aaa");
112 		assert(!s.empty);
113 
114 		s = S("ФЯ");
115 		auto p4 = any(tk!'Ф', tk!'Я').utfString!char;
116 		assert(p4.parse(s, r, err));
117 		assert(r == "ФЯ");
118 		assert(s.empty);
119 	}
120 }
121 
122 
123 struct Map(Parser, alias f) {
124 	alias Stream = ParserStream!Parser;
125 	alias Value = typeof(f(ParserValue!Parser.init));
126 	alias mapper = f;
127 	Parser parser;
128 
129 	bool parse(ref Stream stream, ref Value value, ref Stream.Error err) const {
130 		ParserValue!Parser tmp;
131 		if(parser.parse(stream, tmp, err)){
132 			value = f(tmp);
133 			return true;
134 		}
135 		else
136 			return false;
137 	}
138 }
139 
140 /// Apply a mapping function to the value of parser.
141 public template map(alias f)
142 {
143 	auto map(Parser)(Parser parser)
144 	if(isParser!Parser){
145 		return Map!(Parser, f)(parser);
146 	}
147 }
148 
149 ///
150 unittest {
151 	import std.conv;
152 	import pry.atoms, pry.stream;
153 	alias S = SimpleStream!string;
154 	with(parsers!S) {
155 		auto digits = range!('0', '9').rep.map!(x=>x.to!int);
156 		S s = S("90");
157 		int r;
158 		S.Error err;
159 		assert(digits.parse(s, r, err));
160 		assert(r == 90);
161 		s = S("a");
162 		assert(!digits.parse(s, r, err));
163 		assert(err.location == 0);
164 	}
165 }
166 
167 struct Seq(P...){
168 	alias Stream = ParserStream!(P[0]);
169 	alias Unfiltered = staticMap!(ParserValue, P);
170 	alias Values = EraseAll!(Nothing, Unfiltered);
171 	enum mapIndex(size_t index) = (){
172 		size_t j = 0;
173 		foreach(i, Type; Unfiltered[0..index]){
174 			static if(!is(Type == Nothing)){
175 				j++;
176 			}
177 		}
178 		return j;
179 	}();
180 	P parsers;
181 	
182 	bool parse(ref Stream stream, ref Tuple!Values value, ref Stream.Error err) const {
183 		Nothing nothing;
184 		auto save = stream.mark;
185 		foreach(i, ref p; parsers) {
186 			static if(is(ParserValue!(typeof(p)) == Nothing)) {
187 				if(!p.parse(stream, nothing, err)){
188 					stream.restore(save);
189 					return false;
190 				}
191 			}
192 			else {
193 				enum j = mapIndex!i;
194 				if(!p.parse(stream, value[j], err)){
195 					stream.restore(save);
196 					return false;
197 				}
198 			}
199 		}
200 		return true;
201 	}
202 }
203 
204 /// Apply multiple parsers one after another as a sequence.
205 public auto seq(P...)(P parsers)
206 if(allSatisfy!(isParser, P)){
207 	static if(P.length == 0)
208 		return Nothing();
209 	else
210 		return Seq!P(parsers);
211 }
212 
213 ///
214 unittest {
215 	import pry.atoms, pry.stream;
216 	import std.range.primitives, std.typecons;
217 	alias S = SimpleStream!string;
218 	with(parsers!S) {
219 		auto elements = seq(tk!'a', range!('a', 'd'), tk!'c');
220 		S s = S("abc");
221 		Tuple!(dchar, dchar, dchar) val;
222 		S.Error err;
223 		assert(elements.parse(s, val, err));
224 		assert(s.empty);
225 		assert(val == tuple('a', 'b', 'c'));
226 		s = S("axc");
227 		assert(!elements.parse(s, val, err));
228 		assert(s.front == 'a');
229 		assert(err.location == 1);
230 	}
231 }
232 
233 ///
234 unittest {
235 	import pry.atoms, pry.stream;
236 	alias S = SimpleStream!string;
237 	with(parsers!S) {
238 		auto p = seq(tk!'a', tk!'b', eof);
239 		auto s1 = "abc".stream;
240 		auto s2 = "ab".stream;
241 		S.Error err;
242 		Tuple!(dchar, dchar) val;
243 		assert(!p.parse(s1, val, err));
244 		assert(p.parse(s2, val, err));
245 	}
246 }
247 
248 struct TList(T...){}
249 
250 template commonPrefixLength(T1, T2){
251 	static if(is(T1 == TList!U1, U1...)){
252 		static if(is(T2 == TList!U2, U2...)){
253 			static if(U1.length == 0 || U2.length == 0){
254 				enum commonPrefixLength = 0;
255 			}
256 			else static if(is(Unqual!(U1[0]) == Unqual!(U2[0]))){
257 				enum commonPrefixLength = 1 +
258 					commonPrefixLength!(TList!(U1[1..$]), TList!(U2[1..$]));
259 			}
260 			else {
261 				enum commonPrefixLength = 0;
262 			}
263 		}
264 	}
265 }
266 
267 auto commonPrefix(P1, P2)(P1 p1, P2 p2){
268 	static if(is(P1 : Seq!U1, U1...)){
269 		enum isSeq = true;
270 		alias T1 = TList!U1;
271 	}
272 	else{
273 		enum isSeq = false;
274 		alias T1 = TList!P1;
275 	}
276 	static if(is(P2 : Seq!U2, U2...)){
277 		alias T2 = TList!U2;
278 	}
279 	else{
280 		alias T2 = TList!P2;
281 	}
282 	enum len = commonPrefixLength!(T1,T2);
283 	static if(isSeq)
284 		return seq(p1.parsers[0..len]);
285 	else static if(len)
286 		return seq(p1);
287 	else
288 		return Nothing();
289 }
290 
291 auto commonPrefix(P...)(P p)
292 if(P.length > 2){
293 	return commonPrefix(commonPrefix(p[0], p[1]), p[2..$]);
294 }
295 
296 unittest {
297 	import pry.atoms, pry.stream;
298 	alias S = SimpleStream!string;
299 	with(parsers!S){
300 		auto p1 = seq(tk!'a', tk!'b');
301 		auto p2 = seq(tk!'a');
302 		auto p3 = tk!'a';
303 		auto p4 = seq(tk!'b', tk!'a');
304 		assert(commonPrefix(p1, p2) == seq(tk!'a'));
305 		assert(commonPrefix(p2, p3) == seq(tk!'a'));
306 		assert(commonPrefix(p3, p3) == seq(tk!'a'));
307 		assert(commonPrefix(p3, p1) == seq(tk!'a'));
308 		assert(commonPrefix(p1, p4) == Nothing());
309 		assert(commonPrefix(p3, p4) == Nothing());
310 		assert(commonPrefix(p4, p3) == Nothing());
311 		assert(commonPrefix(p1, p2, p3) == seq(tk!'a'));
312 		assert(commonPrefix(p1, p2, p3, p4) == Nothing());
313 	}
314 }
315 
316 auto suffix(P1, P2)(P1 prefix, P2 parser)
317 if(isParser!P1 && isParser!P2){
318 	static if(is(P1 : Seq!U1, U1...)){
319 		alias T1 = TList!U1;
320 	}
321 	else{
322 		alias T1 = TList!P1;
323 	}
324 	static if(is(P2 : Seq!U2, U2...)){
325 		enum isSeq = true;
326 		alias T2 = TList!U2;
327 	}
328 	else{
329 		enum isSeq = false;
330 		alias T2 = TList!P2;
331 	}
332 	enum len = commonPrefixLength!(T1,T2);
333 	static if(is(T1 : TList!U, U...)){
334 		static assert(len == U.length);
335 	}
336 	static if(isSeq){
337 		return seq(parser.parsers[len..$]);
338 	}
339 	else{
340 		static if(len > 0)
341 			return Nothing();
342 		else
343 			return seq(parser);
344 	}
345 }
346 
347 unittest{
348 	import pry.atoms, pry.stream;
349 	alias S = SimpleStream!string;
350 	with(parsers!S){
351 		auto p1 = seq(tk!'a', tk!'b');
352 		auto p2 = seq(tk!'a');
353 		auto p3 = tk!'a';
354 		auto p4 = seq(tk!'b', tk!'a');
355 		assert(suffix(p2, p1) == seq(tk!'b'));
356 		assert(suffix(p3, p1) == seq(tk!'b'));
357 		assert(suffix(p2, p3) == Nothing());
358 	}
359 }
360 
361 template Unmap(P){
362 	static if(is(P : Map!(U, f), alias f, U)){
363 		alias Unmap = U;
364 	}
365 	else static if(is(P : const(Map!(U, f)), alias f, U)){
366 		alias Unmap = const(U);
367 	}
368 	else{
369 		alias Unmap = P;
370 	}
371 }
372 
373 auto unmap(P)(P parser){
374 	static if(is(P : Map!(U, f), alias f, U)){
375 		return parser.parser;
376 	}
377 	else {
378 		return parser;
379 	}
380 }
381 
382 unittest{
383 	import pry.atoms, pry.stream;
384 	alias S = SimpleStream!string;
385 	with(parsers!S){
386 		auto x = tk!'a'.map!(x => 1);
387 		assert(unmap(x) == tk!'a');
388 		assert(unmap(unmap(x)) == tk!'a');
389 	}
390 }
391 
392 struct Any(P...){
393 	import std.variant, std.typecons;
394 	alias Stream = ParserStream!(P[0]);
395 	alias Values = NoDuplicates!(staticMap!(ParserValue, P));
396 
397 	static if(Values.length == 1)
398 		alias Value = Values[0];
399 	else
400 		alias Value = Algebraic!Values;
401 	
402 	P parsers;
403 	alias Prefix = typeof(extractPrefix());
404 	Prefix prefix;
405 
406 	template mapper(size_t i){
407 		static if(is(P[i] == Map!(U, f), U, alias f))
408 			alias mapper = P[i].mapper;
409 		else
410 			alias mapper = x => x;
411 	}
412 
413 	this(P parsers){
414 		this.parsers = parsers;
415 		prefix = extractPrefix();
416 	}
417 
418 	auto extractPrefix() const {
419 		staticMap!(Unmap, P) unmapped = void;
420 		foreach(i, ref p; parsers){
421 			unmapped[i] = cast()unmap(p);
422 		}
423 		return commonPrefix(unmapped);
424 	}
425 
426 	static auto combine(T1, T2)(T1 prefixValue, T2 suffixValue){
427 		static if(is(T1 == Nothing)){
428 			return suffixValue;
429 		}
430 		else{
431 			return tuple(prefixValue.expand, suffixValue.expand);
432 		}
433 	}
434 
435 	bool parse(ref Stream stream, ref Value value, ref Stream.Error err) const {
436 		static if(is(Prefix == Nothing)){
437 			Nothing prefixValue;
438 		}
439 		else{
440 			ParserValue!Prefix prefixValue;
441 			if(!prefix.parse(stream, prefixValue, err)){
442 				return false;
443 			}
444 		}
445 		Stream.Error current, deepest;
446 		bool ret = false;
447 		foreach(i, ref p; parsers) {
448 			static if(is(Prefix == Nothing))
449 				auto sp = unmap(p);
450 			else
451 				auto sp = suffix(prefix, unmap(p));
452 			alias Suffix = typeof(sp);
453 			static if(is(Suffix == Nothing)){
454 				value = mapper!i(prefixValue.expand);
455 				ret = true;
456 				goto L_end;
457 			}
458 			else {
459 				ParserValue!Suffix suffixValue;
460 				static if(i == 0){
461 					if(sp.parse(stream, suffixValue, deepest)){
462 						value = mapper!i(combine(prefixValue, suffixValue));
463 						return true;
464 					}
465 				}
466 				else {
467 					if(sp.parse(stream, suffixValue, current)){
468 						value = mapper!i(combine(prefixValue, suffixValue));
469 						return true;
470 					}
471 					// pick the deeper error
472 					if(deepest.location < current.location){
473 						deepest = current;
474 					}
475 				}
476 			}
477 		}
478 L_end:
479 		err = deepest;
480 		return ret;
481 	}
482 }
483 
484 /// Try each of provided parsers until one succeeds.
485 public auto any(P...)(P parsers)
486 if(allSatisfy!(isParser, P)){
487 	return Any!P(parsers);
488 }
489 
490 ///
491 unittest {
492 	import pry.atoms, pry.stream;
493 	import std.range.primitives, std.conv, std.variant;
494 	alias S = SimpleStream!string;
495 	with(parsers!S) {
496 		auto digits = range!('0', '9').rep.map!(x => x.to!int);
497 		static assert(isParser!(typeof(digits)));
498 		auto parser = any(tk!'a', digits);
499 		S s = "10a";
500 		S.Error err;
501 		Algebraic!(dchar, int) value;
502 		assert(parser.parse(s, value, err));
503 		assert(value == 10);
504 		assert(parser.parse(s, value, err));
505 		assert(value == cast(dchar)'a');
506 		assert(s.empty);
507 	}
508 }
509 
510 unittest {
511 	import pry.atoms, pry.stream;
512 	alias S = SimpleStream!string;
513 	with(parsers!S) {
514 		auto e = dynamic!int;
515 		e = any(
516 			seq(tk!'0', e).map!(x => 1),
517 			tk!'1'.map!(x => 0)
518 		);
519 		S.Error err;
520 		int val;
521 		S s = S("0001");
522 		assert(e.parse(s, val, err));
523 	}
524 }
525 
526 unittest {
527 	import pry.atoms, pry.stream;
528 	import std.typecons;
529 	alias S = SimpleStream!string;
530 	with(parsers!S) {
531 		auto p = any(
532 			seq(tk!'0', tk!'0'),
533 			seq(tk!'1', tk!'1')
534 		);
535 		S s = "01".stream;
536 		Tuple!(dchar, dchar) value;
537 		S.Error err;
538 		assert(!p.parse(s, value, err));
539 		assert(err.location == 1);
540 	}
541 }
542 
543 
544 struct SkipWs(P) {
545 	private P parser;
546 	alias Stream = ParserStream!P;
547 	alias Value = ParserValue!P;
548 
549 	bool parse(ref Stream s, ref Value v, ref Stream.Error err) const {
550 		import std.uni;
551 		while(!s.empty && isWhite(s.front)) s.popFront();
552 		return parser.parse(s, v, err);
553 	}
554 }
555 
556 /// Skip whitespace at front then apply the `parser`.
557 public auto skipWs(P)(P parser)
558 if(isParser!P && is(ElementType!(ParserStream!P) : dchar)){
559 	return SkipWs!P(parser);
560 }
561 
562 ///
563 unittest {
564 	import pry.atoms, pry.stream;
565 	alias S = SimpleStream!string;
566 	with(parsers!S) {
567 		auto normal = range!('0', '9').rep;
568 		auto skipping = range!('0', '9').skipWs.rep;
569 		auto s1 = "0 9 1".stream;
570 		string r;
571 		S.Error err;
572 		assert(skipping.parse(s1, r, err));
573 		assert(s1.empty);
574 		assert(r == "0 9 1");
575 
576 		auto s2 = "0 9 1".stream;
577 		assert(normal.parse(s2, r, err));
578 		assert(!s2.empty);
579 		assert(r == "0");
580 		assert(s2.front == ' ');
581 	}
582 }
583 
584 struct AAImpl(size_t minTimes, size_t maxTimes, P) {
585 	private P parser;
586 	alias Stream = ParserStream!P;
587 	alias Pair = ParserValue!P;
588 	alias Key = typeof(Pair.init[0]);
589 	alias Value = typeof(Pair.init[1]);
590 
591 	bool parse(ref Stream stream, ref Value[Key] aa, ref Stream.Error err) const {
592 		auto start = stream.mark;
593 		Pair tmp;
594 		size_t i = 0;
595 		for(; i<minTimes; i++) {
596 			if(!parser.parse(stream, tmp, err)){
597 				stream.restore(start);
598 				return false;
599 			}
600 			aa[tmp[0]] = tmp[1];
601 		}
602 		for(; i<maxTimes; i++){
603 			if(!parser.parse(stream, tmp, err)) break;
604 			aa[tmp[0]] = tmp[1];
605 		}
606 		return true;
607 	}
608 }
609 
610 /++
611 	Apply parser of key-value pairs (2-tuples) for minTimes times or more up to maxTimes,
612 	construct an AA out of the results of parsing. 
613 +/
614 public auto aa(size_t minTimes=1, size_t maxTimes=size_t.max, P)(P parser)
615 if(isParser!P && isTuple!(ParserValue!P) && ParserValue!P.length == 2){
616 	return AAImpl!(minTimes, maxTimes, P)(parser);
617 }
618 
619 ///
620 unittest {
621 	import pry.atoms, pry.stream;
622 	import std.conv;
623 	alias S = SimpleStream!string;
624 	with(parsers!S) {
625 		auto p = seq(range!('a', 'z').rep.skipWs, stk!'=', range!('0', '9').rep.skipWs)
626 				.map!(x => tuple(x[0], to!int(x[2]))).aa;
627 		auto s = "a = 1 b = 3 temp = 36".stream;
628 		int[string] table;
629 		S.Error err;
630 		assert(p.parse(s, table, err));
631 		assert(s.empty);
632 		assert(table["a"] == 1);
633 		assert(table["b"] == 3);
634 		assert(table["temp"] == 36);
635 	}
636 }
637 
638 struct Optional(P) {
639 	private P parser;
640 	alias Stream = ParserStream!P;
641 	alias Value = ParserValue!P;
642 
643 	bool parse(ref Stream stream, ref Nullable!Value option, ref Stream.Error err) const {
644 		Value tmp;
645 		if(parser.parse(stream, tmp, err)) {
646 			option = tmp;
647 			return true;
648 		}
649 		option.nullify();
650 		return true;
651 	}
652 }
653 
654 /// Try to apply `parser`, produce null on failure.
655 public auto optional(P)(P parser)
656 if(isParser!P){
657 	return Optional!P(parser);
658 }
659 
660 ///
661 unittest {
662 	import pry.atoms, pry.stream;
663 	alias S = SimpleStream!string;
664 	with(parsers!S){
665 		auto p = range!('a', 'z').optional;
666 		auto s = "a".stream;
667 		Nullable!dchar c;
668 		S.Error err;
669 		assert(p.parse(s, c, err));
670 		assert(c == 'a');
671 		assert(s.empty);
672 		assert(p.parse(s, c, err));
673 		assert(c.isNull);
674 	}
675 }
676 
677 struct Slice(P){
678 	private P parser;
679 	alias Stream = ParserStream!P;
680 	alias Value = ParserValue!P;
681 
682 	bool parse(ref Stream stream, ref Stream.Range range, ref Stream.Error err) const {
683 		auto start = stream.mark();
684 		Value val;
685 		if(parser.parse(stream, val, err)) {
686 			range = stream.slice(start);
687 			return true;
688 		}
689 		return false;
690 	}
691 }
692 
693 /// Apply parser, discard the value and instead produce the slice of parsed stream.
694 public auto slice(P)(P parser)
695 if(isParser!P){
696 	return Slice!P(parser);
697 }
698 
699 ///
700 unittest {
701 	import pry.atoms, pry.stream, std.conv;
702 	alias S = SimpleStream!string;
703 	with(parsers!S){
704 		auto p = seq(tk!'-'.optional, range!('0', '9').rep)
705 						.slice
706 						.map!(x => to!int(x));
707 		auto s = "-13".stream;
708 		int value;
709 		S.Error err;
710 		assert(p.parse(s, value, err));
711 		assert(value == -13);
712 		s = "5".stream;
713 		assert(p.parse(s, value, err));
714 		assert(value == 5);
715 	}
716 }
717 
718 struct Delimited(Item, Delimiter){
719 	private Item item;
720 	private Delimiter delimiter;
721 	alias Stream = ParserStream!Item;
722 	alias Value = ParserValue!Item;
723 
724 	bool parse(ref Stream stream, ref Value[] values, ref Stream.Error err) const {
725 		import std.array;
726 		values = Value[].init;
727 		bool first = true;
728 		Value val;
729 		ParserValue!Delimiter tmp;
730 		auto app = appender!(Value[]);
731 		auto m = stream.mark();
732 		if (item.parse(stream, val, err)){
733 			app.put(val);
734 			for(;;) {
735 				if(!delimiter.parse(stream, tmp, err)) break;
736 				if (item.parse(stream, val, err))
737 					app.put(val);
738 				else {
739 					stream.restore(m);
740 					return false;
741 				}
742 			}
743 		}
744 		values = app.data();
745 		return true;
746 	}
747 }
748 
749 /// Parse a sequence of `item` delimited by `del`
750 public auto delimited(Item, Delimiter)(Item item, Delimiter del)
751 if(isParser!Item && isParser!Delimiter){
752 	return Delimited!(Item, Delimiter)(item, del);
753 }
754 
755 ///
756 unittest{
757 	import pry.atoms, pry.stream, std.conv;
758 	alias S = SimpleStream!string;
759 	with(parsers!S){
760 		auto p = delimited(
761 			range!('0', '9').rep.skipWs.map!(x => to!int(x)),
762 			stk!','
763 		);
764 		auto s = " 2, 4,5".stream;
765 		int[] values;
766 		S.Error err;
767 		assert(p.parse(s, values, err));
768 		assert(values == [2, 4, 5]);
769 		s = "10".stream;
770 		assert(p.parse(s, values, err));
771 		assert(values == [10]);
772 		s = "".stream;
773 		assert(p.parse(s, values, err));
774 		assert(values == []);
775 	}
776 }
777 
778 struct Lookahead(Parser) {
779 	Parser parser;
780 	alias Stream = ParserStream!Parser;
781 	alias Value = ParserValue!Parser;
782 
783 	bool parse(ref Stream stream, ref Nothing _, ref Stream.Error err) const {
784 		auto m = stream.mark();
785 		Value val;
786 		bool r = parser.parse(stream, val, err);
787 		stream.restore(m);
788 		return r;
789 	}
790 }
791 
792 /// Use Parser as lookahead, doesn't consume input stream. 
793 auto lookahead(Parser)(Parser p)
794 if(isParser!Parser){
795 	return Lookahead!Parser(p);
796 }
797 
798 struct NegLookahead(Parser) {
799 	Parser parser;
800 	alias Stream = ParserStream!Parser;
801 	alias Value = ParserValue!Parser;
802 
803 	bool parse(ref Stream stream, ref Nothing _, ref Stream.Error err) const {
804 		auto m = stream.mark();
805 		Value val;
806 		bool r = !parser.parse(stream, val, err);
807 		stream.restore(m);
808 		return r;
809 	}
810 }
811 
812 /// Use Parser as lookahead, doesn't consume input stream. 
813 auto negLookahead(Parser)(Parser p)
814 if(isParser!Parser){
815 	return NegLookahead!Parser(p);
816 }
817 
818 unittest {
819 	import pry.atoms, pry.stream, std.conv;
820 	alias S = SimpleStream!string;
821 	with(parsers!S){
822 		auto p1 = seq(tk!'a', tk!'b'.lookahead);
823 		auto s1 = "ab".stream;
824 		Tuple!dchar val;
825 		S.Error err;
826 		assert(p1.parse(s1, val, err));
827 		assert(val[0] == 'a');
828 		auto p2 = seq(tk!'a', tk!'b'.negLookahead);
829 		s1 = "ab".stream;
830 		assert(!p2.parse(s1, val, err));
831 		auto s2 = "ac".stream;
832 		assert(p2.parse(s2, val, err));
833 	}	
834 }