using compile;
using asm;
using type;

using edu.neu.ccs.demeterf.demfgen.lib;
using edu.neu.ccs.demeterf;

using System.IO;
using System;

// Main Functional Compiler Class
public class Compile{
    static void p(String s){ Console.Write(s); }
    public static void Main(String[] args){
        if(args.Length < 1){
            p(" usage: compile.exe <CodeFile>\n");
        E e = MainC.parse(new FileStream(args[0],FileMode.Open)).e;
            p("\n    Exp: "+e.Print()+"\n");
            p("\n   Type: "+TypeCheck.check(e).Print()+"\n");

            OpList code = new Compile().compile(e);
            p("\n   Code:\n"+code.Print()+"\n");
            ExecStack res = code.eval();
            p("\n   Eval: "+("\n");
            p("\n Stacks: \n"+res+"\n");
        }catch(TypeCheck.TE ex){
            p("\n TypeError: "+ex.Message+"\n\n");
    public OpList compile(E e){
        Traversal comp = new Traversal(new Code3());
        return comp.traverse<OpList>(e, List<ident>.create());

// Generate Code for the Base Language (Arithmetic)
class Code : ID{
    public static OpList single(Opcode o){ return new OpEmpty().append(o); }

    OpList combine(P p){ return single(new Plus()); }
    OpList combine(M m){ return single(new Minus()); }
    OpList combine(T t){ return single(new Times()); }
    OpList combine(D d){ return single(new Divide()); }

    OpList combine(S s, int i){ return single(new Push(i)); }
    OpList combine(C c, OpList op, OpList left, OpList right){
        return right.append(left).append(op);

// Generate Code with the Let/de Bruijn Extension
class Code2 : Code{
    List<ident> update(L let, L.bodyF f, List<ident> s){ return s.push(; }
    OpList combine(V v, ident id, List<ident> s){ return single(new Load(s.index(id))); }
    OpList combine(L let, ident id, OpList e, OpList body){
        return e.append(new Def()).append(body).append(new Undef());

// Generate Code for Boolean Functions and If expressions
class Code3 : Code2{
    private int lnum = 0;
    int fresh(){ int i; lock(this)i = lnum++; return i; }

    OpList combine(LT l){ return single(new Less()); }
    OpList combine(GT g){ return single(new Greater()); }
    OpList combine(EQ e){ return single(new Equal()); }
    OpList combine(AndF a){ return single(new And()); }
    OpList combine(OrF o){ return single(new Or()); }

    OpList combine(I f, OpList c, OpList t, OpList e){
        ident l1 = new ident("else_"+fresh()),
              l2 = new ident("done_"+fresh());
        return c.append(new IfZ(l1)).append(t)
            .append(new Jmp(l2)).append(new Label(l1))
            .append(e).append(new Label(l2));