package accrue.analysis.interprocanalysis;

import polyglot.frontend.AbstractPass;
import polyglot.frontend.ExtensionInfo;
import polyglot.frontend.goals.Goal;
import polyglot.types.SemanticException;
import polyglot.util.ErrorInfo;
import polyglot.util.ErrorQueue;

/**
 * Compiler pass for an interprocedural analysis. 
 * 
 * @param <T> Analysis result type
 */
public class InterProcAnalysisPass<T extends Ordered<T>> extends AbstractPass {

    /**
     * Compiler extension info
     */
    protected final ExtensionInfo extInfo;
    /**
     * Map from procedures to analysis results
     */
    protected final Registrar registrar;
    /**
     * Analysis utility class
     */
    protected final AnalysisFactory<T> factory;

    /**
     * Create a new interprocedural analysis pass
     * 
     * @param extInfo
     *            Compiler extension info
     * @param g
     *            Compiler goal used by Polyglot scheduler
     * @param registrar
     *            Map from procedures to analysis results
     * @param factory
     *            Analysis utility class
     */
    protected InterProcAnalysisPass(ExtensionInfo extInfo, Goal g,
            Registrar registrar, AnalysisFactory<T> factory) {
        super(g);
        this.extInfo = extInfo;
        this.registrar = registrar;
        this.factory = factory;
    }

    /**
     * @return Map from procedures to analysis results
     */
    public Registrar registrar() {
        return this.registrar;
    }

    /**
     * @return Compiler extension info
     */
    public ExtensionInfo extensionInfo() {
        return this.extInfo;
    }

    @Override
    public boolean run() {
        try {
            WorkQueue<T> workQueue = createWorkQueue();
            workQueue.processQueue();
            this.postSuccessfulProcess(workQueue);
            return true;
        }
        catch (SemanticException e) {
            ErrorQueue eq = extInfo.compiler().errorQueue();
            eq.enqueue(ErrorInfo.SEMANTIC_ERROR, e.getMessage(), e.position());
            return false;
        }
    }

    /**
     * Create the analysis work queue of analysis units
     */
    protected WorkQueue<T> createWorkQueue() {
        return new WorkQueue<T>(registrar, extInfo, factory, this);
    }

    /**
     * Post the results of a successful analysis pass
     * 
     * @param analysis work queue of analysis units
     */
    protected void postSuccessfulProcess(WorkQueue<T> workQueue) {
    }
}
