AutumnPrettyPrinter.java

package autumn.lang.compiler;

import autumn.lang.compiler.ast.commons.IConstruct;
import autumn.lang.compiler.exceptions.IncompleteNodeException;
import autumn.lang.compiler.exceptions.RepeatedNodeException;
import autumn.lang.compiler.exceptions.UnprintableNodeException;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.mackenziehigh.autumn.lang.compiler.pretty.PrintingVisitor;
import com.mackenziehigh.autumn.resources.Finished;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.List;

/**
 * An instance of this class can pretty-print an abstract-syntax-tree.
 *
 * <p>
 * Note: The output of this pretty-printer is version-specific.
 * </p>
 *
 * @author Mackenzie High
 */
@Finished("2014/07/12")
public final class AutumnPrettyPrinter
{
    private final PrintStream out;

    /**
     * Constructor.
     *
     * <p>
     * Equivalent:
     * <code>AutumnPrettyPrinter(System.out)</code>
     * </p>
     */
    public AutumnPrettyPrinter()
    {
        this(System.out);
    }

    /**
     * Constructor.
     *
     * @param out is the stream to print to.
     */
    public AutumnPrettyPrinter(final PrintStream out)
    {
        Preconditions.checkNotNull(out);

        this.out = out;
    }

    /**
     * This method retrieves the stream that is being printed to.
     *
     * @return the aforedescribed stream.
     */
    public PrintStream stream()
    {
        return out;
    }

    /**
     * This method prints an abstract-syntax-tree node to the underlying stream.
     *
     * @param node is the AST node to print, which may be the root of an entire tree.
     * @throws UnprintableNodeException if the AST contains a node that is unprintable.
     * @throws IncompleteNodeException if the AST is incomplete.
     * @throws RepeatedNodeException if the AST contains the same node more than once.
     */
    public void print(final IConstruct node)
            throws UnprintableNodeException,
                   IncompleteNodeException,
                   RepeatedNodeException
    {
        Preconditions.checkNotNull(node);

        final PrintingVisitor printer = new PrintingVisitor();

        node.accept(printer);

        final String pretty = printer.buildString();

        out.print(pretty);
    }

    /**
     * This method creates a PrintStream that prints to a StringBuilder using ASCII.
     *
     * <p>
     * Note: The returned stream throws an IOException, when non-ASCII encoded text is encountered.
     * </p>
     *
     * <p>
     * Note: The returned stream cannot be used to print null characters (i.e. ASCII(0)).
     * </p>
     *
     * @param builder is the builder to print ASCII encoded characters to.
     * @return the aforedescribed stream.
     */
    public static PrintStream createStreamASCII(final StringBuilder builder)
    {
        final OutputStream stream = new OutputStream()
        {
            @Override
            public void write(final int character)
                    throws IOException
            {
                if (character > 0 && character <= 127)
                {
                    builder.append((char) character);
                }
                else if (character == 0)
                {
                    throw new IOException("The character cannot be the null-terminator.");
                }
                else
                {
                    throw new IOException("The character must be encodable using ASCII.");
                }
            }
        };

        return new PrintStream(stream);
    }

    /**
     * This method linearizes the nodes in a given abstract-syntax-tree.
     *
     * @param node is the root of the AST.
     * @return the aforedescribed immutable list.
     */
    public static List<IConstruct> nodesOf(final IConstruct node)
    {
        Preconditions.checkNotNull(node);

        final PrintingVisitor printer = new PrintingVisitor();

        node.accept(printer);

        final List<IConstruct> list = ImmutableList.copyOf(printer.visited());

        return list;
    }
}