import edu.rice.cs.mint.runtime.*;

public class SeparableSample4 {
    // public static class MyException extends RuntimeException {
    // public separable MyException() { } // error
    // }
    public static class IntPair {
        public int first;
        public int second;
        public separable IntPair(int f, int s, RuntimeException r) {
            first = f;
            second = s;
            // throw new MyException(); // error
            // throw r; // error
        }
    }
    
    public static class Yikes extends RuntimeException {
        public separable Yikes() { }
    }
    
    public static class Whoa extends Yikes {
    }
    
    public static class OhKay extends RuntimeException {
        public Code<Integer> c;
        public separable OhKay(final int i) {
            c = <| i |>;
        }
    }

    public static class OhKayMethodReturn extends RuntimeException {
        public Code<Integer> foo() { return <| 1 |>; }
        public separable OhKayMethodReturn() {
        }
    }

    public static class OhKayMethodParam extends RuntimeException {
        public void foo(Code<Integer> c) { }
        public separable OhKayMethodParam() {
        }
    }
    
    public static separable void m() throws Throwable {
        // throw new Throwable();
        // throw new RuntimeException();
        // throw new Yikes();
        // throw new Whoa();
        throw new OhKay(1);
	// throw new OhKayMethodReturn();
	// throw new OhKayMethodParam();
        /* RuntimeException e = new RuntimeException () {
            public Code<Integer> meth () { return <| 1 |>; }
        };
        throw e; // error */
    }
    
    //    public separable Code<Integer> method(int i, IntPair p)
    //     throws java.io.IOException { // error
    public separable SafeCode<Integer> method(final int i,
                                              IntPair p,
                                              RuntimeException r) {
        // if (i==1) throw r; // error
        return <| i |>;
    }
    public void run() {
        RuntimeException r = new RuntimeException();
        SafeCode<Integer> c2 = <| 2 |>;
        Code<Integer> c = <|
            `(method(1, new IntPair(0,0,r), r)) +
            `c2 |>;
        System.out.println("c.run() = "+c.run()+" (expected: 3)");
        
        Code<Void> ct = <| { throw new RuntimeException(); } |>; // unsafe
        SafeCode<Void> ct2 = <| { m(); } |>;
        try {
            ct2.run();
        }
        catch(OhKay e) {
            Code<Integer> ec = e.c;
            System.out.println("Scope extrusion! "+ec.run());
        }
        // ct = <| { return; } |>; // error
        // ct = <| { return 5; } |>; // error
    }
    public static void main (String [] args) {
        new SeparableSample4().run();
    }
}
