Diff
Not logged in

Differences From Artifact [d70e48b147acc242]:

To Artifact [c96de2738d81e418]:


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 +}