Package com.redhat.ceylon.compiler.java.codegen

Source Code of com.redhat.ceylon.compiler.java.codegen.BugException

package com.redhat.ceylon.compiler.java.codegen;

import java.util.Arrays;

import com.redhat.ceylon.compiler.typechecker.model.Declaration;
import com.redhat.ceylon.compiler.typechecker.tree.Node;
import com.sun.tools.javac.tree.JCTree.JCExpression;

/**
* <p>Thrown when the code generator is in a seemingly impossible situation
* (i.e. failed assertion of some kind) when it's not feasible to
* return {@link AbstractTransformer#makeErroneous(Node, String) JCErroneous}
* (because there's no Node to hand, or the method does not return
* {@code JCExpression}). Returning {@code JCErroneous} is generally
* preferable since it results it just one downstream javac error, whereas
* failing to generate a declaration will cause downstream javac errors
* for every use site</p>
*
* <h3>At {@code throw} sites</h3>
* <p>The various {@code static}
* factory methods provide convenient ways to create instances for
* common "impossible" circumstances.</p>
*
* <h3>At {@code catch} sites</h3>
* <p>If there is no {@link Node} available at the {@code throw} site,
* the exception can be {@linkplain #associate(Node) associated}
* with one when it is caught.</p>
*
* <p>{@link #addError(Node)} is used to add an error in to the Ceylon tree
* for subsequent reporting via the {@code Log}.
* Alternativly instances can be conveniently transformed into
* a {@code JCErroneous}. In either case it is only possible to add the err
* to the Ceylon tree once.</p>
*
* @see AbstractTransformer#makeErroneous(Node, String)
*/
public class BugException extends RuntimeException {

    private Node node;
   
    private boolean attached;
   
    public BugException() {
        this(null);
    }
   
    public BugException(String message) {
        this(message, null);
    }
   
    public BugException(String message, Exception cause) {
        this(null, message, cause);
    }
   
    public BugException(Node node, String message) {
        this(node, message, null);
    }
   
    public BugException(Node node, String message, Exception cause) {
        super(message == null ? "assertion failed" : message, cause);
        // This is nasty: When we print the errors out following codegen
        // we don't want to dump the whole stack, just the first frame
        // the factory methods would occupy their own uninformative frame
        // so filter out the first frames until we reach one which is not
        // from our class
        StackTraceElement[] stackTrace = getStackTrace();
        String myName = BugException.class.getName();
        int from = 0;
        for (StackTraceElement frame : stackTrace) {
            if (!myName.equals(frame.getClassName())) {
                break;
            }
            from++;
        }
        setStackTrace(Arrays.copyOfRange(stackTrace, from, stackTrace.length));
        this.node = node;
    }
   
    /**
     * Associate this exception with the given node if this exception is
     * not already associated with a node.
     */
    public void associate(Node node) {
        if (this.node == null) {
            this.node = node;
        }
    }

    private Node bestNode(Node fallbackNode) {
        return this.node != null ? this.node : fallbackNode;
    }
   
    /**
     * Add an error to the a node. A {@link CodeGenError}
     * is created with the exception's message and the exception as cause,
     * and is added to the assoicated node (if there is one), and otherwise
     * the given node.
     * @param fallbackNode
     */
    public void addError(Node fallbackNode) {
        if (!this.attached) {
            Node bestNode = bestNode(fallbackNode);
            bestNode.addError(new CodeGenError(bestNode, getMessage(), this));
            this.attached = true;
        }
    }
   
    /**
     * Returns an erroneous node based on the exceptions message, having
     * {@linkplain #addError(Node) added an error to the tree}.
     * @param gen
     * @param fallbackNode
     * @return
     */
    public JCExpression makeErroneous(AbstractTransformer gen, Node fallbackNode) {
        addError(fallbackNode);
        return gen.makeErroneous(bestNode(fallbackNode), getMessage());
    }
   
    /**
     * <p>Used at the end of a {@code if (x instanceof Foo)}/{@code else if (x instanceof Bar)}
     * chain on Node types</pre>
     */
    public static BugException unhandledNodeCase(Node node) {
        return new BugException("unhandled node type " + node.getNodeType());
    }
   
    /**
     * <p>Used at the end of a {@code if (x instanceof Foo)}/{@code else if (x instanceof Bar)}
     * chain on declaration types</p>
     */
    public static BugException unhandledDeclarationCase(Declaration d) {
        return unhandledDeclarationCase(d, null);
    }
    public static BugException unhandledDeclarationCase(Declaration d, Node node) {
        return new BugException(node, "unhandled declaration " + d.getQualifiedNameString() + " with type " + (d == null ? "null" : d.getClass().getSimpleName()));
    }
   
    /**
     * <p>Used as the default case of an enum {@code switch} or at the end of a
     * {@code if (x instanceof Foo)}/{@code else if (x instanceof Bar)}
     * chain on enum elements.</p>
     */
    public static <E extends Enum<E>> BugException unhandledEnumCase(Enum<E> element) {
        return new BugException("unhandled enum case " + element);
    }
   
    /**
     * Used at the end of the
     * {@code if (x instanceof Foo)}/{@code else if (x instanceof Bar)} chain
     */
    public static BugException unhandledCase(Object o) {
        return new BugException("unhandled case " + (o == null ? "null" : o.getClass().toString()));
    }
}
TOP

Related Classes of com.redhat.ceylon.compiler.java.codegen.BugException

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.