high.mackenzie.autumn.lang.compiler.args.Visitor.java Source code

Java tutorial

Introduction

Here is the source code for high.mackenzie.autumn.lang.compiler.args.Visitor.java

Source

package high.mackenzie.autumn.lang.compiler.args;

import autumn.lang.compiler.Autumn;
import autumn.lang.compiler.AutumnProject;
import autumn.lang.compiler.errors.BasicErrorReporter;
import autumn.lang.exceptions.AssertionFailedException;
import autumn.lang.exceptions.AssumptionFailedException;
import autumn.util.test.TestResults;
import com.google.common.collect.Lists;
import com.google.common.io.Resources;
import high.mackenzie.autumn.Main;
import high.mackenzie.autumn.resources.Finished;
import high.mackenzie.snowflake.ITreeNode;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.file.NoSuchFileException;
import java.util.LinkedList;
import java.util.List;

/**
 * An instance of this class is used to process the command-line arguments given to the compiler.
 *
 * @author Mackenzie High
 */
@Finished("2014/08/22")
public final class Visitor extends AbstractVisitor {
    private static interface Invokable {
        public void invoke() throws Exception;
    }

    private static final String HELP = "/high/mackenzie/autumn/resources/help.txt";

    private static final String LICENSE = "/high/mackenzie/autumn/resources/license.txt";

    private static final String VERSION = "/high/mackenzie/autumn/resources/version.txt";

    private String name;

    private static final Autumn cmp = new Autumn();

    /**
     * These are the paths to the jar files.
     */
    private static final LinkedList<File> paths = Lists.newLinkedList();

    /**
     * These are the command-line arguments to pass to the interpreted program.
     */
    private static final LinkedList<String> args = Lists.newLinkedList();

    /**
     * This field is used to temporarily store a single argument.
     */
    private String argument;

    private void visitChildren(final ITreeNode node) {
        for (ITreeNode kid : node.children()) {
            visit(kid);
        }
    }

    /**
     * This method resolves the project folder.
     *
     * <p>
     * Imagine that you try to run an Autumn project from somewhere deep within the project.
     * Autumn must resolve the outer most folder in the project folder.
     * That is precisely what this method does.
     * </p>
     *
     * @return the resolved project folder.
     */
    private static File resolveProject() {
        File p = new File(System.getProperty("user.dir"));

        while (isProject(p) == false && p.getParent() != null) {
            p = p.getParentFile();
        }

        return p;
    }

    /**
     * This method determines whether a folder is a project folder.
     *
     * @param folder is a possible project folder.
     * @return true, iff the file represents a project folder.
     */
    private static boolean isProject(final File folder) {
        return folder.isDirectory() && !folder.isHidden() && new File(folder, "src").exists()
                && new File(folder, "lib").exists() && new File(folder, "test").exists();
    }

    /**
     * This method resolves the name of a file.
     *
     * <p>
     * The file may already be resolved, or the file may be in the current directory,
     * or the file may be in the home directory.
     * </p>
     *
     * @param file is the file to resolve.
     * @return the actual path to the file.
     * @throws NoSuchFileException if the file cannot be found.
     */
    private static File resolve(final File file) throws NoSuchFileException {
        final File CURRENT = new File(System.getProperty("user.dir"));

        final File HOME = new File(System.getProperty("user.home"));

        final boolean atom = file.getPath().contains(System.getProperty("file.separator")) == false;

        final File possibility1 = new File(CURRENT, file.getName());

        final File possibility2 = new File(HOME, file.getName());

        if (file.exists()) {
            return file;
        } else if (atom && possibility1.exists()) {
            return possibility1;
        } else if (atom && possibility2.exists()) {
            return possibility2;
        } else {
            throw new NoSuchFileException(file.toString());
        }
    }

    /**
     * This method generalizes the running of a project.
     *
     * <p>
     * This method alleviates the need for separate complex methods
     * for running, testing, and debugging Autumn programs.
     * </p>
     *
     * @param function is used to invoke the appropriate method in the Autumn object.
     */
    private static void run(final Invokable function) {
        /**
         * Load the project.
         */
        try {
            final File project = resolveProject();

            cmp.loadProject(project);
        } catch (IOException ex) {
            System.out.println("The project coult not be loaded.");
            ex.printStackTrace(System.out);
        }

        /**
         * Execute the script.
         */
        try {
            function.invoke();
        } catch (ClassNotFoundException ex) {
            System.out.println("The main-class could not be found.");
            ex.printStackTrace(System.out);
        } catch (NoSuchMethodException ex) {
            System.out.println("The main(String[]) function could not be found.");
            ex.printStackTrace(System.out);
        } catch (InvocationTargetException ex) {
            if (ex.getCause() instanceof AssertionFailedException) {
                System.out.println("Assertion Failed:");
                System.out.println("  File: " + ((AssertionFailedException) ex.getCause()).file());
                System.out.println("  Line: " + ((AssertionFailedException) ex.getCause()).line());
            }

            if (ex.getCause() instanceof AssumptionFailedException) {
                System.out.println("Assumption Failed:");
                System.out.println("  File: " + ((AssumptionFailedException) ex.getCause()).file());
                System.out.println("  Line: " + ((AssumptionFailedException) ex.getCause()).line());
            }

            ex.getCause().printStackTrace(System.out);
        } catch (IllegalAccessException ex) {
            ex.printStackTrace(System.out);
        } catch (MalformedURLException ex) {
            ex.printStackTrace(System.out);
        } catch (Exception ex) {
            ex.printStackTrace(System.out);
        }
    }

    public void printHelp() {
        final URL url = Resources.getResource(Main.class, HELP);

        try {
            System.out.println(Resources.toString(url, Charset.defaultCharset()));
        } catch (Exception ex) {
            ex.printStackTrace(System.out);
            return;
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void visitUnknown(final ITreeNode node) {
        visitChildren(node);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void visit_case_help(final ITreeNode node) {
        printHelp();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void visit_case_version(final ITreeNode node) {
        final URL url = Resources.getResource(Main.class, VERSION);

        try {
            System.out.println(Resources.toString(url, Charset.defaultCharset()));
        } catch (Exception ex) {
            ex.printStackTrace(System.out);
            return;
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void visit_case_license(final ITreeNode node) {
        final URL url = Resources.getResource(Main.class, LICENSE);

        try {
            System.out.println(Resources.toString(url, Charset.defaultCharset()));
        } catch (Exception ex) {
            ex.printStackTrace(System.out);
            return;
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void visit_case_run(final ITreeNode node) {
        visitChildren(node);

        final Invokable function = new Invokable() {
            @Override
            public void invoke() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException,
                    IllegalAccessException {
                /**
                 * Run the program.
                 */
                cmp.run(args);
            }
        };

        run(function);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void visit_case_test(final ITreeNode node) {
        visitChildren(node);

        final Invokable function = new Invokable() {
            @Override
            public void invoke() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException,
                    IllegalAccessException {
                final TestResults results = cmp.test();

                results.print(System.out);
            }
        };

        run(function);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void visit_case_execute(final ITreeNode node) {
        visitChildren(node);

        final Invokable function = new Invokable() {
            @Override
            public void invoke() throws Exception {
                final List<File> jars = new LinkedList<File>();

                for (File path : paths) {
                    jars.add(resolve(path));
                }

                AutumnProject.execute(jars, args.toArray(new String[0]));
            }
        };

        run(function);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void visit_case_compile(final ITreeNode node) {
        visitChildren(node);

        try {
            final File userdir = new File(System.getProperty("user.dir"));

            final AutumnProject project = new AutumnProject(userdir, new BasicErrorReporter(System.out));

            project.compile();
        } catch (IOException ex) {
            System.out.println("Error - The project could not be compiled.");
            ex.printStackTrace(System.out);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void visit_case_create(final ITreeNode node) {
        visitChildren(node);

        try {
            final File userdir = new File(System.getProperty("user.dir"));

            System.out.println("Current Directory = " + userdir);
            System.out.println("Project Name = " + name);

            AutumnProject.create(new File(userdir, name));
        } catch (IOException ex) {
            System.out.println("Error - The project could not be created.");
            ex.printStackTrace(System.out);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void visit_name(final ITreeNode node) {
        visitChildren(node);

        name = args.get(0).trim();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void visit_path(final ITreeNode node) {
        visitChildren(node);

        paths.add(new File(argument));
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void visit_arg(final ITreeNode node) {
        visitChildren(node);

        args.add(argument);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void visit_qstring(final ITreeNode node) {
        final String text = node.childAt(2).text().substring(0, node.length() - 2);

        argument = text;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void visit_pstring(final ITreeNode node) {
        final String text = node.childAt(1).text();

        argument = text;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void visit_error(final ITreeNode node) {
        printHelp();
    }
}