import compile.*;
import type.*;

import edu.neu.ccs.demeterf.*;
import edu.neu.ccs.demeterf.demfgen.lib.*;

// TypeChecking
public class TypeCheck extends ID{
    static class TE extends RuntimeException{ TE(String s){super(s);}}
    static Type intT = new Int();
    static Type boolT = new Bool();
    
    Type combine(S s){ return intT; }

    Op combine(Op o){ return o; }
    Type combine(C c, ArithOp op, Int l, Int r){ return intT; }
    Type combine(C c, CompOp op, Int l, Int r){ return boolT; }
    Type combine(C c, BoolOp op, Bool l, Bool r){ return boolT; }

    Type combine(C c, Op op, Type l, Type r){
        throw new TE("Op ("+op.print()+") doesn\'t match Args: "+
                     l.print()+" and "+r.print());
    }

    Type combine(I ife, Bool c, Int t, Int e){ return t; }
    Type combine(I ife, Bool c, Bool t, Bool e){ return t; }
    Type combine(I ife, Bool c, Type t, Type e){
        throw new TE("If Branches Don\'t Match: "+t.print()+" != "+e.print());
    }
    
    Type combine(L l, ident id, Type e, E body, List<Pair> te){
        return check(body, te.push(new Pair(id,e)));
    }
    Type combine(V v, final ident id, List<Pair> te){
        return te.find(new List.Pred<Pair>(){
                public boolean huh(Pair p){ return p.id.equals(id); }}).t;
    }

    // Cache the Traversal... and a few static methods for recursion
    static Traversal trav = 
        new Traversal(new TypeCheck(),Control.bypass("compile.L.body"));
    static Type check(E e){ return check(e, List.<Pair>create()); }
    static Type check(E e, List<Pair> te){ return trav.traverse(e, te); }
}