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, (_) { });