Differences From Artifact [d70e48b147acc242]:
- File
tricks/tricks.d
- 2010-11-10 12:38:54 - part of checkin [38fcc662be] on branch trunk - cleaned up documentation comments (user: kinaba) [annotate]
To Artifact [c96de2738d81e418]:
- File
tricks/tricks.d
- 2010-11-13 02:48:58 - part of checkin [1c01f44f52] on branch trunk - simplepatternmatch (user: kinaba) [annotate]
4 4 *
5 5 * Common tricks and utilities for programming in D.
6 6 */
7 7 module tricks.tricks;
8 8 import tricks.test;
9 9 import std.array : appender;
10 10 import std.format : formattedWrite;
11 -import core.exception : AssertError;
11 +import core.exception;
12 +import std.traits;
13 +import std.typetuple;
12 14
13 15 /// Simple Wrapper for std.format.doFormat
14 16
15 17 string sprintf(string fmt, T...)(T params)
16 18 {
17 19 auto writer = appender!string();
18 20 formattedWrite(writer, fmt, params);
................................................................................
204 206 /*mixin*/
205 207 template SimpleClass()
206 208 {
207 209 mixin SimpleConstructor;
208 210 mixin SimpleCompare;
209 211 mixin SimpleToString;
210 212 }
213 +
214 +/// Simple PatternMatcher
215 +
216 +/*mixin*/
217 +template SimplePatternMatch()
218 +{
219 + SPM_Return!(PP) match(string fn=__FILE__, size_t ln=__LINE__, PP...)(PP pts)
220 + {
221 + foreach(i,_; pts)
222 + {
223 + alias pts[i] pt; // bug? pts[i]-->pt do not work
224 + static if(__traits(compiles, SPM_isMatchTag(pt)))
225 + {
226 + if( auto v = cast(pt.dynamicType)this )
227 + return pt(v.tupleof);
228 + }
229 + else
230 + static if(__traits(compiles, SPM_isMatchAny(pt)))
231 + {
232 + return pt();
233 + }
234 + else
235 + {
236 + if( auto v = cast(SPM_PTT!(pt)[0])this )
237 + return pt(v);
238 + }
239 + }
240 + SPM_throwAssertError(fn, ln, "pattern matching failure");
241 + assert(false);
242 + }
243 +}
244 +
245 +/// Pattern case clause
246 +
247 +SPM_MatchTag!(T, fn) when(T, alias fn)()
248 +{
249 + SPM_MatchTag!(T, fn) m;
250 + return m;
251 +}
252 +
253 +/// Pattern case clause
254 +
255 +SPM_MatchAny!(fn) otherwise(alias fn)()
256 +{
257 + SPM_MatchAny!(fn) m;
258 + return m;
259 +}
260 +
261 +// implementation detail of SimplePatternMatch
262 +
263 +void SPM_throwAssertError(T...)(T t) { core.exception.onAssertErrorMsg(t); }
264 +
265 +struct SPM_MatchTag(T, alias fn)
266 +{
267 + alias T dynamicType;
268 + auto opCall(typeof(T.tupleof) s) { return fn(s); }
269 +}
270 +
271 +struct SPM_MatchAny(alias fn)
272 +{
273 + auto opCall() { return fn(); }
274 +}
275 +
276 +template SPM_PTT(alias p)
277 +{
278 + alias ParameterTypeTuple!(p) SPM_PTT;
279 +}
280 +
281 +template SPM_Each(P)
282 +{
283 + static if(__traits(compiles, SPM_isMatchTag(P.init)))
284 + alias typeof(P(P.dynamicType.tupleof)) SPM_Each;
285 + else
286 + static if(__traits(compiles, SPM_isMatchAny(P.init)))
287 + alias typeof(P()) SPM_Each;
288 + else
289 + alias ReturnType!(P) SPM_Each;
290 +}
291 +
292 +template SPM_aVoid(T:void, TS...) { alias SPM_aVoid!(TS) SPM_aVoid; }
293 +template SPM_aVoid(T, TS...) { alias TypeTuple!(T,SPM_aVoid!(TS)) SPM_aVoid; }
294 +template SPM_aVoid() { alias TypeTuple!() SPM_aVoid; }
295 +
296 +template SPM_Return(PP...)
297 +{
298 + alias CommonType!(SPM_aVoid!(staticMap!(SPM_Each, PP))) SPM_Return;
299 +}
300 +
301 +void SPM_isMatchTag(T,alias fn)(SPM_MatchTag!(T,fn)){}
302 +void SPM_isMatchAny(alias fn)(SPM_MatchAny!(fn)){}
303 +
304 +unittest
305 +{
306 + static abstract class Base {
307 + mixin SimplePatternMatch;
308 + }
309 + class D1 : Base {
310 + int x;
311 + real y;
312 + mixin SimpleConstructor;
313 + }
314 + class D2 : Base {
315 + string s;
316 + mixin SimpleConstructor;
317 + }
318 + class D3 : Base {
319 + int[int]m;
320 + mixin SimpleConstructor;
321 + }
322 +
323 + Base d1 = new D1(1, 2.3);
324 + Base d2 = new D2("foobar");
325 + Base d3 = new D3(null); (cast(D3)d3).m[1]=10;
326 +
327 + // normal dispatch
328 + assert_eq( d1.match(
329 + (D1 x){return 1;},
330 + (D2 x){return 2;},
331 + ), 1);
332 + assert_eq( d2.match(
333 + (D1 x){return 1;},
334 + (D2 x){return 2;},
335 + ), 2);
336 + assert_throw!AssertError( d3.match(
337 + (D1 x){return 1;},
338 + (D2 x){return 2;},
339 + ));
340 + assert_eq( d3.match(
341 + (D1 x){return 1;},
342 + (D2 x){return 2;},
343 + (Base x){return 3;},
344 + ), 3);
345 + assert_eq( d2.match(
346 + (D1 x){return 1;},
347 + (D2 x){return 2;},
348 + (Base x){return 3;},
349 + ), 2);
350 + assert_eq( d2.match(
351 + (D1 x){return 1;},
352 + (Base x){return 3;},
353 + (D2 x){return 2;},
354 + ), 3);
355 +
356 + // member decomposing match
357 + assert_eq( d1.match(
358 + when!(D1, (x, y){return x + cast(int)y;}),
359 + when!(D2, (x){return x.length;}),
360 + when!(D3, (x){return x[1];}),
361 + ), 3);
362 + assert_eq( d2.match(
363 + when!(D1, (x, y){return x + cast(int)y;}),
364 + when!(D2, (x){return x.length;}),
365 + when!(D3, (x){return x[1];}),
366 + ), 6);
367 + assert_eq( d3.match(
368 + when!(D1, (x, y){return x + cast(int)y;}),
369 + when!(D2, (x){return x.length;}),
370 + when!(D3, (x){return x[1];}),
371 + ), 10);
372 + assert_throw!AssertError( d3.match(
373 + when!(D1, (x, y){return x + cast(int)y;}),
374 + when!(D2, (x){return x.length;}),
375 + ));
376 + assert_eq( d2.match(
377 + when!(D1, (x, y){return x + cast(int)y;}),
378 + when!(D2, (x){return x.length;}),
379 + otherwise!({return 999;}),
380 + ), 6);
381 + assert_eq( d2.match(
382 + when!(D1, (x, y){return x + cast(int)y;}),
383 + otherwise!({return 999;}),
384 + when!(D2, (x){return x.length;}),
385 + ), 999);
386 +}