D Paste by miasma
Description: Design by Contract 1.1 -- released into the public domain
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 | module dbct; import tango.io.Stdout; alias char[] string; /** * Implements design by contract * - contract inheritance * - remembers old values (only shallow copy for now) */ // >>>> // >>>> ugly ctfe stuff begins // >>>> string strip(string s) { int a, b = s.length; while (a < s.length && isWhiteSpace(s[a])) a++; while (b > 0 && isWhiteSpace(s[b-1])) b--; return s[a..b]; } string head(string s) { int a; while (a < s.length && !isWhiteSpace(s[a])) a++; return s[0..a]; } string headPar(string s) { int a; while (a < s.length && ((!isWhiteSpace(s[a]) && s[a] != '(' && s[a] != ',' && s[a] != ')') || a==0)) a++; if (a < s.length && s[a] == '(') a++; return s[0..a]; } string methodName(string name, string suffix = "") { string tmp = strip(name), tmp2; tmp = tmp[head(tmp).length..$]; tmp = strip(tmp); tmp2 = headPar(tmp)[0..$-1]; tmp = tmp[headPar(tmp).length..$]; if (suffix != "") tmp2 ~= suffix ~ "(" ~ tmp; return tmp2; } string methodCall(string name, string suffix = "") { string tmp, tmp2; tmp = strip(name); tmp = strip(tmp[head(tmp).length..$]); tmp2 = headPar(tmp); tmp = strip(tmp[headPar(tmp).length..$]); tmp2 = tmp2[0..$-1] ~ suffix ~ "("; string old; while (tmp.length) { string w = headPar(tmp); if (w == "," || w == ")") tmp2 ~= old ~ w ~ " "; old = w; tmp = strip(tmp[w.length..$]); } return tmp2; } bool isWhiteSpace(char c) { return (c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\v' || c == '\f'); } string method(string signature, string _in, string _out, string _body) { string retType = head(strip(signature)); string retType2 = retType == "void" ? "" : retType ~ " result"; retType = retType == "void" ? "" : "result"; string outSig = methodName(signature) ~ "_out("; string baseMet = "static if (is(typeof(this) xxx == super) && is(typeof(xxx[0]."~methodName(signature); string speshul = `__speshul_old_"~typeof(this).stringof~"`; return // "old object" `mixin("static if (!is(typeof(this.` ~ speshul ~ `))) private typeof(this) ` ~ speshul ~ `;");` ~ // in contract baseMet ~ "_in)) && "~ (_in=="" ? "1" : "0") ~ ") {} else { protected void " ~ methodName(signature, "_in") ~ "{" ~ `mixin("`~speshul~` = new typeof(this)();");` ~ `mixin("foreach(__speshul_idx, __speshul_v; this.tupleof) { `~speshul~`.tupleof[__speshul_idx] = __speshul_v; }");` ~ _in ~ "}}" ~ // out contract "protected void " ~ outSig ~ retType2 ~ ")" ~ "{" ~ baseMet ~ "_out))) super."~methodName(signature)~"_out("~retType~");" ~ (_in == "" ? "" : `mixin("auto old = `~speshul~`;");`) ~ _out ~ "}" ~ // method signature signature ~ // second in part "in {" ~ methodCall(signature, "_in") ~ ";}" ~ // second out part "out" ~ (retType == "" ? "" : "("~retType~")") ~ "{" ~ outSig ~ retType ~ ")"~ "; }" ~ // method body "body {" ~ _body ~ "}"; } string method(string signature, string _body) { return method(signature, "", "", _body); } // >>>> // >>>> ugly ctfe stuff ends // >>>> // // USAGE // class base { mixin(method( // signature `int foobar(int i, int j)`, // in `Stdout("base.in\n");`, //``, // out `Stdout("base.out\n");`, // body `return 0;` )); } class derived : base { int a, b; mixin(method( // signature `int foobar(int i, int j)`, // in `Stdout("derived.in\n");`, // out `Stdout(old.a).newline; Stdout("derived.out\n");`, // body `a = 42; return 0;` )); } void main() { auto b = new derived; auto c = new derived; b.foobar(1,2); b.foobar(1,2); } |