D Paste by miasma
Description: Design by Contract 1.1 -- released into the public domain
Hide line numbers

Create new paste
Post a reply
View replies

Paste:
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);
}

Replies:

    (some replies deleted)