1 /**
2   Combinators
3 
4   Copyright: 2017 Yuxuan Shui
5 */
6 module sdpc.combinators;
7 import sdpc.primitives;
8 import std.traits,
9        std.string,
10        std.stdio,
11        std.typetuple,
12        std.range;
13 
14 @safe :
15 ///Match pattern `begin func end`, return the result of func.
16 struct between(alias begin, alias func, alias end) {
17 	static auto opCall(R)(R i) if (isForwardRange!R) {
18 		alias PR = typeof(func(i));
19 		auto ret1 = begin(i);
20 		static assert(is(typeof(ret1).ErrType: PR.ErrType));
21 		if (!ret1.ok)
22 			return PR(ret1.err);
23 
24 		auto ret = func(ret1.cont);
25 		if (!ret.ok)
26 			return ret;
27 
28 		auto ret2 = end(ret.cont);
29 		if (!ret2.ok)
30 			return PR(ret2.err);
31 		static if (is(PR.DataType == void))
32 			return PR(ret2.cont);
33 		else
34 			return PR(ret2.cont, ret.v);
35 	}
36 }
37 
38 ///
39 unittest {
40 	import sdpc.parsers;
41 	auto i = "(asdf)";
42 	auto r = between!(token!"(", token!"asdf", token!")")(i);
43 	assert(r.ok);
44 	assert(!r.cont.length);
45 }
46 
47 ///Match any of the given pattern, stop when first match is found. All parsers
48 ///must return the same type.
49 struct choice(T...) {
50 	static auto opCall(R)(R i) if (isForwardRange!R && allSameType!(staticMap!(ParserReturnType!R, T))) {
51 		alias PR = typeof(T[0](i));
52 		alias RT = ParseResult!(R, PR.DataType, PR.ErrType[T.length]);
53 		PR.ErrType[T.length] err;
54 		foreach(id, p; T) {
55 			auto ret = p(i);
56 			if (ret.ok)
57 				return RT(ret.cont, ret.v);
58 			err[id] = ret.err;
59 		}
60 		return RT(err[]);
61 	}
62 }
63 
64 /**
65   Match pattern `p delim p delim p ... p delim p`
66 
67   Return data type will be an array of p's return data type
68 */
69 struct chain(alias p, alias delim, bool allow_empty=false) {
70 	static auto opCall(R)(R i) if (isForwardRange!R) {
71 		auto ret = p(i);
72 		alias T = typeof(ret);
73 		static if (is(T.DataType == void))
74 			alias RT = ParseResult!(R, void, T.ErrType);
75 		else
76 			alias RT = ParseResult!(R, T.DataType[], T.ErrType);
77 		if (!ret.ok) {
78 			static if (allow_empty)
79 				return RT(ret.cont, []);
80 			else
81 				return RT(ret.err);
82 		}
83 
84 		static if (!is(T.DataType == void))
85 			T.DataType[] res;
86 		res ~= ret.v;
87 
88 		auto last_range = ret.cont;
89 		while(true) {
90 			auto dret = delim(last_range);
91 			if (!dret.ok)
92 				break;
93 			auto pret = p(dret.cont);
94 			if (!pret.ok)
95 				break;
96 			static if (!is(T.DataType == void))
97 				res ~= pret.v;
98 			last_range = pret.cont;
99 		}
100 
101 		static if (is(T.DataType == void))
102 			return RT(last_range);
103 		else
104 			return RT(last_range, res);
105 	}
106 }
107 
108 ///
109 unittest {
110 	import sdpc.parsers;
111 	import std.algorithm;
112 
113 	alias calc = transform!(chain!(number!(), token!"+"), (x) => x.reduce!"a+b");
114 	auto i = "1+2+3+4+5";
115 	auto r = calc(i);
116 	assert(r.ok);
117 	assert(r.v == 15);
118 }
119 
120 /**
121   Match `func*` or `func+`
122 
123   Return array of func's result
124 */
125 struct many(alias func, bool allow_none = false) {
126 	static auto opCall(R)(R i) if (isForwardRange!R) {
127 		alias PR = typeof(func(i));
128 		static if (is(PR.DataType == void)) {
129 			alias RT = ParseResult!(R, void, PR.ErrType);
130 			size_t count = 0;
131 		} else {
132 			alias RT = ParseResult!(R, PR.DataType[], PR.ErrType);
133 			PR.DataType[] res;
134 		}
135 
136 		auto last_range = i.save;
137 		while(true) {
138 			auto ret = func(last_range);
139 			if (!ret.ok) {
140 				static if (is(PR.DataType == void)) {
141 					if (allow_none || count > 0)
142 						return RT(last_range);
143 					else
144 						return RT(ret.err);
145 				} else {
146 					if (allow_none || res.length > 0)
147 						return RT(last_range, res);
148 					else
149 						return RT(ret.err);
150 				}
151 			}
152 			static if (!is(PR.DataType == void))
153 				res ~= [ret.v];
154 			else
155 				count++;
156 			last_range = ret.cont;
157 		}
158 	}
159 }
160 
161 ///
162 unittest {
163 	import sdpc.parsers;
164 	auto i = "abcdaaddcc";
165 	alias abcdparser = many!(choice!(token!"a", token!"b", token!"c", token!"d"));
166 	auto r2 = abcdparser(i);
167 	assert(r2.ok);
168 	assert(!r2.cont.length);
169 
170 	i = "abcde";
171 	auto r3 = abcdparser(i);
172 	assert(r3.ok); //Parse is OK because 4 char are consumed
173 	assert(r3.cont.length); //But the end-of-buffer is not reached
174 }
175 
176 private struct DTTuple(T...) {
177 	import std.typetuple;
178 	import std.meta;
179 	enum notVoid(T) = !is(T.T == void);
180 	template idMatch(uint id) {
181 		enum idMatch(T) = T.id == id;
182 	}
183 	alias E = Enumerate!T;
184 	alias E2 = Filter!(notVoid, E);
185 	private TypeTuple!E2 data;
186 
187 	ref auto v(uint id)() {
188 		enum rid = staticIndexOf!(E[id], E2);
189 		static assert(rid != -1);
190 		return data[rid].value;
191 	}
192 }
193 
194 /**
195   Appply a sequence of parsers one after another.
196 
197   Don't use tuple as data type in any of the parsers. The return
198   data type is a special type of tuple. To get the data of each of
199   the parsers, use `ParseResult.v.v!index`, where `index` is the
200   index of the desired parser in `T`.
201 */
202 struct seq(T...) {
203 	static auto opCall(R)(R i) if (isForwardRange!R) {
204 		alias GetDT(A) = A.DataType;
205 		alias GetET(A) = A.ErrType;
206 		alias PRS = staticMap!(ParserReturnType!R, T);
207 		alias PDT = staticMap!(GetDT, PRS);
208 		static assert(allSameType!(staticMap!(GetET, PRS)));
209 
210 		alias RT = ParseResult!(R, DTTuple!PDT, PRS[0].ErrType);
211 		DTTuple!PDT res;
212 		auto last_range = i.save;
213 		foreach(id, p; T) {
214 			auto ret = p(last_range);
215 			if (!ret.ok)
216 				return RT(ret.err);
217 			static if (!is(PRS[id].DataType == void))
218 				res.v!id = ret.v;
219 			last_range = ret.cont;
220 		}
221 		return RT(last_range, res);
222 	}
223 }
224 
225 ///
226 unittest {
227 	import sdpc.parsers;
228 	auto i = "abcde";
229 	auto r4 = seq!(token!"a", token!"b", token!"c", token!"d", token!"e")(i);
230 	assert(r4.ok);
231 	assert(r4.v.v!0 == "a");
232 	assert(r4.v.v!1 == "b");
233 	assert(r4.v.v!2 == "c");
234 	assert(r4.v.v!3 == "d");
235 	assert(r4.v.v!4 == "e");
236 
237 	auto r5 = seq!(token!"a")(i); //seq with single argument.
238 	assert(r5.ok);
239 	assert(r5.v.v!0 == "a");
240 }
241 
242 /** Optionally matches `p`
243 
244   Return data type will be a Nullable of `p`'s data type
245 */
246 struct optional(alias p) {
247 	static auto opCall(R)(R i) if (isForwardRange!R) {
248 		import std.typecons;
249 		auto r = p(i);
250 		alias PR = typeof(r);
251 		alias RT = ParseResult!(R, Nullable!(PR.DataType), PR.ErrType);
252 		if (!r.ok)
253 			return RT(i, Nullable!(PR.DataType).init);
254 		else
255 			return RT(i, nullable(r.v));
256 	}
257 }
258 
259 ///
260 unittest {
261 	import sdpc.parsers;
262 
263 	auto i = "asdf";
264 	auto r6 = optional!(token!"x")(i);
265 	assert(r6.ok);
266 	assert(r6.v.isNull);
267 
268 	auto r7 = optional!(token!"a")(i);
269 	assert(r7.ok);
270 	assert(!r7.v.isNull);
271 }
272 
273 /// Match `u` but doesn't consume anything from the input range
274 struct lookahead(alias u, bool negative = false){
275 	static auto opCall(R)(R i) if (isForwardRange!R) {
276 		auto r = u(i);
277 		alias PR = typeof(r);
278 		alias RT = ParseResult!(R, void, PR.ErrType);
279 		static if (negative) {
280 			if (r.ok)
281 				return RT(RT.ErrType.init);
282 			else
283 				return RT(i);
284 		} else {
285 			if (r.ok)
286 				return RT(i);
287 			else
288 				return RT(r.err);
289 		}
290 	}
291 }
292 
293 ///
294 unittest {
295 	import sdpc.parsers;
296 
297 	// Accept "asdf" if followed by "g"
298 	alias p = seq!(token!"asdf", lookahead!(token!"g"));
299 	auto i = "asdfg";
300 	auto r1 = p(i);
301 	assert(r1.ok);
302 	assert(r1.cont == "g", r1.cont);
303 
304 	i = "asdff";
305 	auto r2 = p(i);
306 	assert(!r2.ok);
307 }
308 
309 ///Skip `p` zero or more times
310 alias skip(alias p) = discard!(many!(p, true));
311 
312 ///Match `p` but discard the result
313 alias discard(alias p) = transform!(p, (_) { });