Merge remote branch 'master'
[prop.git] / tests / test_rc1.pcc
blobb688ed37c08cc4fa9f45da00fd519e7165100825
1 //
2 //  Testing reference counting with the rewriting features.
3 //  This test is created by modifying rewriting.pcc in this directory
4 //
5 #include <new>
6 #include <iostream.h>
8 int balance = 0;
9 //
10 //  Define an algebraic datatype.  Currently, rewriting can only be 
11 //  performed on datatypes(and not views) in Prop.  
12 //  If replacement is to be performed on a datatype, then it should
13 //  be declared using the ``rewrite'' qualifier.
14 //  We'll use garbage collection with rewriting.
16 datatype EXP :: traced rewrite = om
17                                | num (int)
18                                | var (char)
19                                | add (EXP, EXP)
20                                | sub (EXP, EXP)
21                                | mul (EXP, EXP)
22                                | div (EXP, EXP)
23 public:
24 {  inline void * operator new (size_t n)
25       { balance++; return new char [n]; }
26    inline void   operator delete (void * c)
27       { balance--; delete [] ((char*)c); }
30 instantiate datatype EXP;
33 //  Define a method that prints an expression.  This is a simple
34 //  inductive definition
36 ostream& operator << (ostream& f, EXP e)
37 {  match (e) {
38       om:       { return f << "om"; }
39    |  num i:    { return f << i; }
40    |  var v:    { return f << v; }
41    |  add(a,b): { return f << '(' << a << " + " << b << ')'; }
42    |  sub(a,b): { return f << '(' << a << " - " << b << ')'; }
43    |  mul(a,b): { return f << '(' << a << " * " << b << ')'; }
44    |  div(a,b): { return f << '(' << a << " / " << b << ')'; }
45    }
49 //  Define the interface to a ``rewriting class.''  A rewriting class 
50 //  is simply a C++ class with rewriting rules attached.  In real programs
51 //  this definition should be placed in some definition (i.e. .ph) files.
52 //  
53 //  In parenthesis, we must list all datatypes involved.   Unlike
54 //  simple pattern matching, rewriting can involve a set of mutually
55 //  recursive (or mutually exclusive, if desired) datatype definitions.
56 //  So in general this is a comma delimited list.   
58 //  In this example it involves only the datatype EXP.
60 rewrite class Simplify (EXP)
61 {  // nothing here for now.
65 //  Now we define the rewriting rules in the rewriting class Simplify.  These
66 //  rules should be placed in an implementation file (.pcc, .pC, .pc++ etc).
68 //  In this brief sample class we have some rules that perform 
69 //  simple constant folding and strength reduction.
71 //  Currently, all the rules for a rewrite class must be placed in
72 //  the same rewrite construct.  This will probably change in the future
73 //  once I work out the details on incremental tree automata compilation.
75 rewrite Simplify {
76    add (num 0, x):                    rewrite(x); 
77 |  add (x, num 0):                    rewrite(x);  
78 |  sub (x, num 0):                    rewrite(x);  
79 |  mul (x, num 0):                    rewrite(num(0));  
80 |  mul (num 0, x):                    rewrite(num(0));  
81 |  mul (x, num 1):                    rewrite(x);       
82 |  mul (num 1, x):                    rewrite(x); 
83 |  mul (x, num 2):                    rewrite(add(x,x)); 
84 |  mul (num 2, x):                    rewrite(add(x,x)); 
85 |  div (x, num 1):                    rewrite(x);        
86 |  add (num x, num y):                rewrite(num(x + y)); 
87 |  sub (num x, num y):                rewrite(num(x - y)); 
88 |  mul (num x, num y):                rewrite(num(x * y)); 
89 |  div (num x, num y) where (y != 0): rewrite(num(x / y)); 
90 |  div (_, num 0):                    { /* cout << "Division by zero!\n"; */ }
91 |  div (zero as num 0, x):            rewrite(zero); 
95 //  Now defines the function that uses all this stuff.
97 void do_my_stuff()
99    //
100    // Instantiate a rewriting class 
101    //
102    Simplify sim;
103    EXP t1, term, term2;
105    for (int trials = 1; trials < 10000; trials++) {
106       //
107       // (0 + x * 2) / (1 * 5 + 1 * 3) / (0 / y);
108       //
109       t1 = div(div(add(num(0), mul(var('x'),num(2))), 
110                    add(mul(num(1), num(5)),mul(num(1),num(3)))),
111                div(num(0),var('y')));
112       term = mul(t1,t1);
114       //
115       //  Rewrite the big term above.
116       // 
117       // cout << "Before: " << term << '\n';
118       sim(term);
119       // cout << "After: " << term << '\n';
121       //
122       //  Rewrite it again.  It should have no effect since the term
123       //  is already in normal form.
124       //
125       sim(term);
126       // cout << "Again (should have no effect): " << term << '\n';
128       //
129       //  Rewrite some other term.
130       //
131       term2 = add(sub(num(3),num(3)), var('z'));
132       // cout << "Before: " << term2 << '\n';
133       sim(term2);
134       // cout << "After: " << term2 << '\n';
135    }
138 int main() 
140    cout << "Now performing some rewrites and generating some garbage.\n"
141            "This test is identical to the garbage collection test 'test_gc3'\n"
142            "except that reference counting is used.   On all platforms\n"
143            "that I've tested reference counting is actually slower.\n"
144          << flush;
145   
146    do_my_stuff();
148    cout << "Finished.  Now cleaning up.\n"
149            "Balance = " << balance << '\n';
150    if (balance != 0) {
151       cerr << "Bug in reference counting!\n";
152       return 1;
153    }
154    return 0;