Last active
September 4, 2017 08:50
-
-
Save alphaKAI/122189b2515f0d72aa23950d93a8ea44 to your computer and use it in GitHub Desktop.
toy pattern matching in D
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import std.functional, | |
std.typecons, | |
std.traits, | |
std.meta; | |
class PatternIsNull {} | |
class PatternWithValue(P = PatternIsNull, F: R delegate(), R: R) { | |
P pattern; | |
F func; | |
this (F func) { | |
this.func = func; | |
} | |
this (P pattern, F func) { | |
this.pattern = pattern; | |
this.func = func; | |
} | |
bool match(PX)(PX that_pattern) { | |
static if (is(P == PX)) { | |
return that_pattern == this.pattern; | |
} else static if (isCallable!P && is(ReturnType!P == bool) && is(Parameters!P[0] == PX)) { | |
return this.pattern(that_pattern); | |
} else { | |
return false; | |
} | |
} | |
} | |
auto _(PT, FT)(PT p, FT f) { | |
static if (isSomeFunction!FT) { | |
static if (is(FT == R function(), R: R)) { | |
return new PatternWithValue!(PT, R delegate())(p, f.toDelegate); | |
} else { | |
return new PatternWithValue!(PT, FT)(p, f); | |
} | |
} else { | |
return new PatternWithValue!(PT, FT delegate())(p, delegate FT () { return f; }); | |
} | |
} | |
auto _(FT)(FT f) { | |
static if (isSomeFunction!FT) { | |
static if (is(FT == R function(), R: R)) { | |
return new PatternWithValue!(PatternIsNull, R delegate())(f.toDelegate); | |
} else { | |
return new PatternWithValue!()(f); | |
} | |
} else { | |
return new PatternWithValue!(PatternIsNull, FT delegate())(delegate FT () { return f; }); | |
} | |
} | |
void checkMP_value(MP...)(MP mp) { | |
static assert (mp.length); | |
enum bool value_mode = is(typeof(mp[0]) == PatternWithValue!(T, F), T: T, F: F); | |
foreach (e; mp) { | |
static if (value_mode) { | |
static assert (is(typeof(e) == PatternWithValue!(T, F), T: T, F: F)); | |
} else { | |
static assert (is(typeof(e) == PatternWithValue!(T, F), T: T, F: F) | |
|| is(typeof(e) == PatternWithType!(T, F), T: T, F: F)); | |
} | |
} | |
} | |
auto match(X, MP...)(X x, MP mp) { | |
checkMP_value(mp); | |
enum validate = (is(MP[0] == PatternWithValue!(T, F), T: T, F: F) | |
|| is(MP[0] == PatternWithType!(T, F), T: T, F: F)); | |
static assert (validate); | |
PatternWithValue!(PatternIsNull, F) otherwise; | |
bool exist_otherwise; | |
foreach (e; mp) { | |
static if (is(typeof(e) == PatternWithValue!(PatternIsNull, F))) { | |
otherwise = e; | |
exist_otherwise = true; | |
continue; | |
} else { | |
if (e.match(x)) { | |
return e.func(); | |
} | |
} | |
} | |
if (!exist_otherwise) { | |
return otherwise.func(); | |
} else { | |
throw new Error("No pattern matched"); | |
} | |
} | |
class PatternWithType(P = PatternIsNull, F: R delegate(), R: R) { | |
F func; | |
this (F func) { | |
this.func = func; | |
} | |
bool match(X)() { | |
static if (is(P == X)) { | |
return true; | |
} else { | |
return false; | |
} | |
} | |
bool match(X)(X x) { | |
if (!isBuiltinType!P && !isPointer!X) { | |
return cast(P)x !is null; | |
} else { | |
return false; | |
} | |
} | |
} | |
auto _(PT, FT)(FT f) { | |
static if (isSomeFunction!FT) { | |
static if (is(FT == R function(), R: R)) { | |
return new PatternWithType!(PT, R delegate())(f.toDelegate); | |
} else { | |
return new PatternWithType!(PT, FT)(f); | |
} | |
} else { | |
return new PatternWithType!(PT, FT delegate())(delegate FT () { return f; }); | |
} | |
} | |
void checkMP_type(MP...)(MP mp) { | |
static assert (mp.length); | |
foreach (e; mp) { | |
static assert (is(typeof(e) == PatternWithType!(T, F), T: T, F: F) | |
|| is(typeof(e) == PatternWithValue!(PatternIsNull, F), F: F)); | |
} | |
} | |
auto match(T, MP...)(MP mp) { | |
checkMP_type(mp); | |
enum validate = (is(MP[0] == PatternWithValue!(PatternIsNull, F), F: F) | |
|| is(MP[0] == PatternWithType!(T, F), T: T, F: F)); | |
static assert (validate); | |
PatternWithValue!(PatternIsNull, F) otherwise; | |
bool exist_otherwise; | |
foreach (e; mp) { | |
static if (is(typeof(e) == PatternWithValue!(PatternIsNull, F))) { | |
otherwise = e; | |
exist_otherwise = true; | |
continue; | |
} else { | |
if (e.match!T()) { | |
return e.func(); | |
} | |
} | |
} | |
if (!exist_otherwise) { | |
return otherwise.func(); | |
} else { | |
throw new Error("No pattern matched"); | |
} | |
} | |
import std.stdio; | |
interface AorB {} | |
class A : AorB {} | |
class B : AorB {} | |
enum E { A,B } | |
string pz() { return "pattern z"; } | |
void main() { | |
string x = "z"; | |
x.match( | |
"x"._({ writeln("pattern x"); }), | |
"y"._({ writeln("pattern y"); }), | |
((string z) => z == "z")._({writeln("pattern z");}), | |
_({ writeln("otherwise"); })); | |
string ret = x.match( | |
"x"._(() => "pattern x"), | |
"y"._(() => "pattern y"), | |
((string z) => z == "z")._(pz), | |
_(() => ("otherwise"))); assert (ret == "pattern " ~ x); | |
string ret2 = x.match( | |
"x"._("pattern x"), | |
"y"._("pattern y"), | |
((string z) => z == "z")._("pattern z"), | |
_("otherwise")); assert (ret2 == "pattern " ~ x); | |
match!(typeof(1))( | |
_!string({ writeln("pattern string"); }), | |
_!int({ writeln("pattern int"); }), | |
_({ writeln("otherwise"); })); | |
AorB aorb = new A; | |
aorb.match( | |
_!A({ writeln("pattern A"); }), | |
_!B({ writeln("pattern B"); }), | |
_({ writeln("otherwise"); })); | |
E eab = E.B; | |
eab.match( | |
E.A._({ writeln("pattern A"); }), | |
E.B._({ writeln("pattern B"); }), | |
_({ writeln("otherwise"); })); | |
string ret3 = eab.match( | |
E.A._( "pattern E.A" ), | |
E.B._( "pattern E.B" ), | |
_("otherwise")); assert (ret3 == "pattern E.B"); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment