#include "axllib.as"

macro {
        A == Array;
        SI == SingleInteger;
};

import from SI;
import from Machine;
import from TextWriter;

define MyRing: Category == BasicType with {
    new : () -> %;
    +: (%, %) -> %;
}

MyInt: MyRing with {
        set!: (SI) -> %;
        coerce: SI-> %;
        coerce: % -> SI;
        << : (TextWriter, %) -> TextWriter;
} == SingleInteger add {
        Rep == SingleInteger;

        import from SingleInteger;
        import from TextWriter;

        new () : % == per 0;

        coerce (s: SI) : % == per s;
        coerce (v: %) : SI == rep v;

        set! (s: SI) : % == {
                vv : % := new();
                i := rep vv;
                i := s;
                per i;
        };

        (a: %) + (b: %) : % == per (rep a + rep b);
        (a: %) * (b: %) : % == per (rep a * rep b);

        (t:TextWriter) << (r :%) : TextWriter == {
                t << rep r;
        }
}

Matrix (elemType: MyRing, m: SingleInteger, n: SingleInteger): MyRing with {
    apply : (%, SingleInteger, SingleInteger) -> elemType;
    set! : (%, SI, SI, elemType) -> elemType;
}
== add {
    import from SingleInteger;
    import from elemType;
    B == A elemType;
    import from B;
    Rep == A B;
    import from Rep;

    new () : % == per (new (m, (new (n, new()$elemType ))));

    apply (a: %, i: SingleInteger, j: SingleInteger) : elemType == {
        r := rep a;
        (r i) j
    }

    set! (vv:%, i:SI, j: SI, e: elemType): elemType == {
        a1 := rep vv;
        a2 := a1(i);
        a2(j) := e;
        e;
    }

    (a:%) = (b:%) : Boolean == ((rep a) = (rep b)) :: Boolean;
        (t:TextWriter) << (r :%) : TextWriter == {
                for i in 1..n repeat {
                        for j in 1..m repeat {
                                t << r(i, j) << " ";
                        }
                        t << newline;
                }
                t
        }

        sample : % == new ();

        + (a: %, b: %): % == {
                c: % := new ();
                r := rep c;
                for i in 1..m repeat {
                        for j in 1..n repeat {
                                (r i) j := a (i, j) + b (i, j);
                        }
                }
                c;
        }

}

main():() == {
        import from SI;
        import from TextWriter;
        M == Matrix (MyInt, 2, 2);
        default q: SI;
        default my: MyInt := new();
        default v, w, z: M;
        import from M;
        import from TextWriter;

        v:= new();
        w := new();
        z := new();

        my := coerce(1);

        print << my << newline;

        for i in 1..2 repeat {
                for j in 1..2 repeat {
                        v(i, j) := my;
                        w(i, j) := my;
                        z(i, j) := my;
                }
        }

        z := v + w;

        print << "v = " << newline;
        print << v << newline ;
        print << "w = " << newline;
        print << w << newline;
        print << "z = " << newline;
        print << z << newline ;
}

main();