//Mike Maxim
//Main translate visitor base class

package edu.cmu.cs.l3.translate;

import edu.cmu.cs.l3.general.*;
import edu.cmu.cs.l3.frame.*;
import edu.cmu.cs.l3.semant.*;
import edu.cmu.cs.l3.absyn.*;
import edu.cmu.cs.l3.errormsg.*;
import edu.cmu.cs.l3.tree.*;
import java.util.*;

public abstract class Translate implements Visitor {

    public Translate(Frame curframe, ErrorMsg errormsg,
                     TranslateEnvironment table) {
        m_curframe = curframe;
        m_errorMsg = errormsg;
        m_table = table;
        switch (m_memTranMode) {
            case IRMEM:
                m_memtran = new TranslateMemoryIR();
                break;
            case RTMEM:
                m_memtran = new TranslateMemoryRT();
                break;
        }
        m_memtran.setErrorHandler(m_errorMsg);
    }

    public static final int OFFSET = 0, SIZE = 1;
    public static final int NULLERROR = 0, SIZEERROR = 1, ZEROERROR = 2;
    public static final int IRMEM = 0, RTMEM = 1;

    public static int m_memTranMode = IRMEM;

    public TranslateExpression chooseTranslator(ASExpression exp) {
        if (exp.getTypeInfo().getSemantType()instanceof TyBool) {
            if (exp instanceof ASBoolConstant) {
                return new TranslateExpressionValueCx(m_curframe, m_errorMsg,
                    m_table);
            }
            else if ((exp instanceof ASOpExpression &&
                     ( (ASOpExpression) exp).getOperatorClass() ==
                     ASOpExpression.RELATIONAL)) {
                return new TranslateExpressionRelCx(m_curframe, m_errorMsg,
                    m_table);
            }
            else if (exp instanceof ASOpExpression &&
                     ( (ASOpExpression) exp).getOperatorClass() ==
                     ASOpExpression.BOOLOP) {
                return new TranslateExpressionOpCx(m_curframe, m_errorMsg,
                    m_table);
            }
        }

        return new TranslateExpressionEx(m_curframe, m_errorMsg, m_table);
    }

    protected IRExpression allocInitExp(Ty ty) throws TranslateException {

        if (ty instanceof TyRecord)
            return allocRecordInit( (TyRecord) ty);
        else if (ty instanceof TyPointer) {
            IRExpression ntemp = new IRTemp(m_curframe.allocLocalTemp());
            return new IRESeq(new IRSeq(new IRComment("Null Deposit"),
                                     new IRMove(ntemp, m_memtran.getNullTemp())), ntemp);
        }
        else
            return new IRConst(0);
    }

    protected IRExpression allocRecordInit(TyRecord rty) throws
        TranslateException {

        List fields = rty.getFields();
        IRStatement initstm = null;
        IRExpression exp = null;
        int i;

        IRExpression memget = m_memtran.allocateHeapMemory(m_curframe,
            new IRConst(fields.size()), false);
        IRTemp mem = new IRTemp(m_curframe.allocLocalTemp());

        for (i = fields.size() - 1; i >= 0; i--) {
            Ty fty = (Ty) fields.get(i);
            if (fty instanceof TyRecord)
                exp = allocRecordInit( (TyRecord) fty);
            else if (fty instanceof TyBinding)
                exp = allocRecordInit( (TyRecord)((TyBinding)fty).getBinding());
            else if (fty instanceof TyPointer) {
                IRExpression ntemp = new IRTemp(m_curframe.allocLocalTemp());
                exp = new IRESeq(new IRSeq(new IRComment("Null Deposit"),
                                     new IRMove(ntemp, m_memtran.getNullTemp())), ntemp);
            }
            else {
                exp = null;
            }
            if (exp != null) {
                if (initstm == null) {
                    initstm = new IRMove(m_memtran.thinPointerAccess(m_curframe,
                        mem, new IRConst(i)), exp);
                }
                else {
                    initstm = new IRSeq(new IRMove(m_memtran.thinPointerAccess(
                        m_curframe, mem, new IRConst(i)), exp),
                                        initstm);
                }
            }
        }

        if (initstm != null)
            return new IRESeq(new IRSeq(new IRMove(mem, memget), initstm), mem);
        else
            return new IRESeq(new IRMove(mem, memget), mem);
    }

    public int getNumErrors() {
        return m_numerrors;
    }

    protected void error(int pos, String message) {
        m_errorMsg.error(pos, "TRANSLATE: " + message);
        m_numerrors++;
    }

    protected Frame m_curframe;
    protected TranslateMemory m_memtran;
    protected TranslateEnvironment m_table;
    protected ErrorMsg m_errorMsg;
    protected static int m_numerrors = 0;
}