package accrue.analysis.ext;

import java.util.Map;

import polyglot.ast.MethodDecl;
import polyglot.types.Type;
import polyglot.util.Position;
import polyglot.util.SerialVersionUID;
import polyglot.visit.DataFlow;
import polyglot.visit.FlowGraph;
import polyglot.visit.FlowGraph.EdgeKey;
import polyglot.visit.FlowGraph.Peer;
import accrue.AccrueUtil;
import accrue.analysis.interprocanalysis.DataFlowDispatch;
import accrue.analysis.pointer.ReferenceVariable;
import accrue.analysis.pointer.RegisterPointerStmtsVisitor;
import accrue.analysis.pointer.StmtRegistrar;
import accrue.analysis.pointer.StmtRegistrar.CodeInfo;

public class ExtMethodDecl extends ExtProcedureDecl {
    private static final long serialVersionUID = SerialVersionUID.generate();

    @Override
    public void registerPointerStmts(StmtRegistrar registrar,
            RegisterPointerStmtsVisitor v) {
        MethodDecl md = (MethodDecl) this.node();
        if (AccrueUtil.isMainMethod(md.procedureInstance())) {
            // this is the main method, public static void main(String[])
            // make the argument point to a new array...

            Type stringArray = md.methodInstance().formalTypes().get(0);
            ReferenceVariable argsArray =
                    registrar.registerStaticAlloc(stringArray,
                                                  true,
                                                  "main-args",
                                                  md.position());

            CodeInfo codeInfo = registrar.getCodeInfo(md);
            ReferenceVariable formalLN = codeInfo.formals.get(0);

            registrar.addAssignment(formalLN,
                                    argsArray,
                                    md.position(),
                                    v.currentCode());

            // the contents points to some string literals...
            // Treat it as a special kind of alloc site for now.
            ReferenceVariable lits =
                    registrar.registerStaticAlloc(v.typeSystem().String(),
                                                  true,
                                                  "main-args",
                                                  Position.COMPILER_GENERATED);

            registrar.addAssignmentToField(argsArray,
                                           StmtRegistrar.ARRAY_CONTENTS,
                                           v.typeSystem().String(),
                                           lits,
                                           md.position(),
                                           v.currentCode());

        }
        super.registerPointerStmts(registrar, v);
    }

    @Override
    public <DFItem extends DataFlow.Item> Map<EdgeKey, DFItem> flowDispatch(
            DataFlowDispatch<DFItem> dataflow, DFItem dfIn,
            FlowGraph<DFItem> graph, Peer<DFItem> peer) {
        MethodDecl n = (MethodDecl) this.node();
        return dataflow.flowMethodDecl(n, dfIn, graph, peer);
    }

}
