edu.clemson.cs.r2jt.absynnew.ResolveCompiler.java Source code

Java tutorial

Introduction

Here is the source code for edu.clemson.cs.r2jt.absynnew.ResolveCompiler.java

Source

/**
 * ResolveCompiler.java
 * ---------------------------------
 * Copyright (c) 2014
 * RESOLVE Software Research Group
 * School of Computing
 * Clemson University
 * All rights reserved.
 * ---------------------------------
 * This file is subject to the terms and conditions defined in
 * file 'LICENSE.txt', which is part of this source code package.
 */
package edu.clemson.cs.r2jt.absynnew;

import edu.clemson.cs.r2jt.misc.*;
import edu.clemson.cs.r2jt.parsing.ResolveParser;
import edu.clemson.cs.r2jt.typeandpopulate.ModuleIdentifier;
import edu.clemson.cs.r2jt.typeandpopulate2.AnalysisPipeline;
import edu.clemson.cs.r2jt.typeandpopulate2.MathSymbolTableBuilder;
import org.antlr.v4.runtime.ANTLRFileStream;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.Token;
import org.jgrapht.Graphs;
import org.jgrapht.graph.DefaultDirectedGraph;
import org.jgrapht.graph.DefaultEdge;
import org.jgrapht.graph.EdgeReversedGraph;
import org.jgrapht.traverse.DepthFirstIterator;
import org.jgrapht.traverse.GraphIterator;
import org.jgrapht.traverse.TopologicalOrderIterator;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.*;

public class ResolveCompiler {

    public static final String VERSION = "15.13.02a";

    public static final String FLAG_SECTION_NAME = "General";

    private static final String FLAG_DESC_LIB_DIR = "Specify the projects workspace directory.";

    private static final String FLAG_DESC_EXTENDED_HELP = "Displays all flags including development flags.";

    private static final String FLAG_DESC_HELP = "Displays this help information.";

    public static final Flag FLAG_HELP = new Flag(FLAG_SECTION_NAME, "help", FLAG_DESC_HELP);

    public static final Flag FLAG_EXTENDED_HELP = new Flag("General", "xhelp", FLAG_DESC_EXTENDED_HELP);

    public static final Flag FLAG_NO_DEFAULT_IMPORTS = new Flag("General", "nostdimport",
            "Prevents the compiler from importing default facilities.");

    public static final Flag FLAG_LIB_DIR = new Flag(FLAG_SECTION_NAME, "lib", FLAG_DESC_LIB_DIR,
            new String[] { "libDir" }, new String[] { System.getProperty("user.dir") });

    public static final ResolveParserFactory PARSER_FACTORY = new ResolveParserFactory();

    public static final List<String> NATIVE_EXT = Collections
            .unmodifiableList(Arrays.asList("co", "fa", "mt", "en", "rb"));

    public static final List<String> NON_NATIVE_EXT = Collections.unmodifiableList(Arrays.asList("java", "c", "h"));

    private final List<String> myTargetFiles = new ArrayList<String>();

    private final String myLibDirectory;

    public final FlagManager myFlagManager;

    public final MathSymbolTableBuilder mySymbolTable = new MathSymbolTableBuilder();

    public final Map<ModuleIdentifier, File> myFiles = new HashMap<ModuleIdentifier, File>();
    public final Map<ModuleIdentifier, ModuleAST> myModules = new HashMap<ModuleIdentifier, ModuleAST>();

    public ResolveCompiler(String[] args) {
        setUpFlagDependencies();
        try {
            myFlagManager = new FlagManager(args);
        } catch (FlagDependencyException fde) {
            throw new IllegalArgumentException(fde.getMessage());
        }
        myLibDirectory = myFlagManager.getFlagArgument(FLAG_LIB_DIR, "libDir");
        handleArgs();
    }

    protected final void handleArgs() {
        if (myFlagManager.isFlagSet(FLAG_HELP)) {
            help();
            exit(0);
        } else {
            version();
        }
        for (String s : myFlagManager.getRemainingArgs()) {
            if (s.charAt(0) != '-') { // filename
                if (!myTargetFiles.contains(s)) {
                    myTargetFiles.add(s);
                }
            } else {
                UnderliningErrorListener.internalError("unrecognized flag " + s);
            }
        }
        //Todo: Sanity check lib directory (make sure it's valid, exists, etc)
    }

    public void compile() {
        try {
            for (String target : myTargetFiles) {
                File currentFile = new File(target);
                if (!currentFile.isAbsolute()) {
                    currentFile = new File(myLibDirectory, target);
                }

                ModuleAST targetModule = createModuleAST(currentFile);
                myFiles.put(new ModuleIdentifier(targetModule), currentFile);
                myModules.put(new ModuleIdentifier(targetModule), targetModule);

                DefaultDirectedGraph<ModuleIdentifier, DefaultEdge> g = new DefaultDirectedGraph<ModuleIdentifier, DefaultEdge>(
                        DefaultEdge.class);
                g.addVertex(new ModuleIdentifier(targetModule));
                findDependencies(g, targetModule);

                AnalysisPipeline analysisPipe = new AnalysisPipeline(this, mySymbolTable);
                //CodeGenPipeline codegenPipe =
                //        new CodeGenPipeline(this, )
                for (ModuleIdentifier m : getCompileOrder(g)) {
                    //System.out.println("populating: " + m);
                    analysisPipe.process(m);
                    //codegenPipe.process(m);
                    //verificationPipe.process(m);
                }
            }
        } catch (Throwable e) {
            Throwable cause = e;
            while (cause != null && !(cause instanceof SrcErrorException)) {
                cause = cause.getCause();
            }
            if (cause == null) {
                if (e instanceof RuntimeException) {
                    throw (RuntimeException) e;
                }
                throw new RuntimeException(e);
            } else {
                SrcErrorException see = (SrcErrorException) cause;
                UnderliningErrorListener.INSTANCE.semanticError(see.getOffendingToken(), e.getMessage());
            }
        }
    }

    private void findDependencies(DefaultDirectedGraph g, ModuleAST root) {
        for (Token importRequest : root.getImports().getImportsExcluding(ImportCollectionAST.ImportType.EXTERNAL)) {

            File file = findResolveFile(importRequest.getText(), NATIVE_EXT);
            ModuleAST module = myModules.get(importRequest);

            if (module == null) {
                module = createModuleAST(file);

                myModules.put(id(module), module);
                myFiles.put(id(module), file);
            }

            if (root.getImports().inCategory(ImportCollectionAST.ImportType.IMPLICIT, importRequest)) {
                if (!module.appropriateForImport()) {
                    throw new IllegalArgumentException("invalid import " + module.getName()
                            + "; cannot import module of " + "type: " + module.getClass());
                }
            }
            if (pathExists(g, id(module), id(root))) {
                throw new CircularDependencyException("circular dependency detected");
            }
            Graphs.addEdgeWithVertices(g, id(root), id(module));
            findDependencies(g, module);
        }
        addFilesForExternalImports(root);
    }

    protected boolean pathExists(DefaultDirectedGraph g, ModuleIdentifier src, ModuleIdentifier dest) {
        //If src doesn't exist in g, then there is obviously no path from
        //src -> ... -> dest
        if (!g.containsVertex(src)) {
            return false;
        }
        GraphIterator<ModuleIdentifier, DefaultEdge> iterator = new DepthFirstIterator<ModuleIdentifier, DefaultEdge>(
                g, src);

        while (iterator.hasNext()) {
            ModuleIdentifier next = iterator.next();
            //we've reached dest from src -- a path exists.
            if (next.equals(dest)) {
                return true;
            }
        }
        return false;
    }

    protected List<ModuleIdentifier> getCompileOrder(DefaultDirectedGraph g) {
        List<ModuleIdentifier> result = new ArrayList<ModuleIdentifier>();

        EdgeReversedGraph<ModuleIdentifier, DefaultEdge> reversed = new EdgeReversedGraph<ModuleIdentifier, DefaultEdge>(
                g);

        TopologicalOrderIterator<ModuleIdentifier, DefaultEdge> dependencies = new TopologicalOrderIterator<ModuleIdentifier, DefaultEdge>(
                reversed);
        while (dependencies.hasNext()) {
            result.add(dependencies.next());
        }
        return result;
    }

    protected static ModuleIdentifier id(ModuleAST m) {
        return new ModuleIdentifier(m);
    }

    private void addFilesForExternalImports(ModuleAST m) {
        Set<Token> externals = m.getImports().getImportsOfType(ImportCollectionAST.ImportType.EXTERNAL);

        for (Token externalImport : externals) {
            File file = findResolveFile(externalImport.getText(), NON_NATIVE_EXT);
            myFiles.put(new ModuleIdentifier(externalImport), file);
        }
    }

    private File findResolveFile(String baseName, List<String> extensions) {
        try {
            FileLocator l = new FileLocator(baseName, extensions);
            Files.walkFileTree(new File(myLibDirectory).toPath(), l);
            return l.getFile();
        } catch (IOException ioe) {
            throw new RuntimeException(ioe.getMessage());
        }
    }

    private ModuleAST createModuleAST(File file) {
        try {
            ResolveParser parser = PARSER_FACTORY.createParser(new ANTLRFileStream(file.getAbsolutePath()));
            ParserRuleContext start = parser.module();
            return TreeUtil.createASTNodeFrom(start);
        } catch (IOException ioe) {
            throw new RuntimeException(ioe);
        }
    }

    public static void main(String[] args) {
        ResolveCompiler resolve = new ResolveCompiler(args);
        resolve.compile();
    }

    /**
     * <p>Prints compiler usage and flag related information to standard
     * output. Note: messages printed are actually formed in the
     * <code>description</code> field of that particular <code>Flag</code>.</p>
     */
    private void help() {
        System.out.println("RESOLVE Compiler Version " + VERSION);
        System.out.println(FlagDependencies.getListingString(myFlagManager.isFlagSet(FLAG_EXTENDED_HELP)));
    }

    /**
     * <p>This method sets up dependencies between compiler flags.  If you are
     * integrating your module into the compiler flag management system, this is
     * where to do it.</p>
     */
    private synchronized static void setUpFlagDependencies() {
        if (!FlagDependencies.isSealed()) {
            setUpFlags();
            //Your module here!
            FlagDependencies.seal();
        }
    }

    private static void setUpFlags() {
        FlagDependencies.addImplies(FLAG_EXTENDED_HELP, FLAG_HELP);
    }

    public void version() {
        System.out.println("RESOLVE Compiler Version " + VERSION);
    }

    public void exit(int e) {
        System.exit(e);
    }
}