001: /*
002: * Copyright 2007 Google Inc.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005: * use this file except in compliance with the License. You may obtain a copy of
006: * the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013: * License for the specific language governing permissions and limitations under
014: * the License.
015: */
016: package com.google.gwt.dev.jjs;
017:
018: import java.util.ArrayList;
019: import java.util.List;
020:
021: /**
022: * Indicates the compiler encountered an unexpected and unsupported state of
023: * operation.
024: */
025: public class InternalCompilerException extends RuntimeException {
026:
027: /**
028: * Information regarding a node that was being processed when an
029: * InternalCompilerException was thrown.
030: */
031: public static final class NodeInfo {
032:
033: private final String className;
034: private final String description;
035: private final SourceInfo sourceInfo;
036:
037: private NodeInfo(String className, String description,
038: SourceInfo sourceInfo) {
039: this .className = className;
040: this .description = description;
041: this .sourceInfo = sourceInfo;
042: }
043:
044: /**
045: * Returns the name of the Java class of the node.
046: */
047: public String getClassName() {
048: return className;
049: }
050:
051: /**
052: * Returns a text description of the node; typically toString().
053: */
054: public String getDescription() {
055: return description;
056: }
057:
058: /**
059: * Returns the node's source info, if available; otherwise <code>null</code>.
060: */
061: public SourceInfo getSourceInfo() {
062: return sourceInfo;
063: }
064: }
065:
066: /**
067: * Tracks if there's a pending addNode() to avoid recursion sickness.
068: */
069: private static final ThreadLocal<InternalCompilerException> pendingICE = new ThreadLocal<InternalCompilerException>();
070:
071: private final List<NodeInfo> nodeTrace = new ArrayList<NodeInfo>();
072:
073: /**
074: * Constructs a new exception with the specified node, message, and cause.
075: */
076: public InternalCompilerException(HasSourceInfo node,
077: String message, Throwable cause) {
078: this (message, cause);
079: addNode(node);
080: }
081:
082: /**
083: * Constructs a new exception with the specified message.
084: */
085: public InternalCompilerException(String message) {
086: super (message);
087: }
088:
089: /**
090: * Constructs a new exception with the specified message and cause.
091: */
092: public InternalCompilerException(String message, Throwable cause) {
093: super (message, cause);
094: }
095:
096: /**
097: * Adds a node to the end of the node trace. This is similar to how a stack
098: * trace works.
099: */
100: public void addNode(HasSourceInfo node) {
101: InternalCompilerException other = pendingICE.get();
102: if (other != null) {
103: // Avoiding recursion sickness: Yet Another ICE must have occurred while
104: // generating info for a prior ICE. Just bail!
105: return;
106: }
107:
108: String className = null;
109: String description = null;
110: SourceInfo sourceInfo = null;
111: try {
112: pendingICE.set(this );
113: className = node.getClass().getName();
114: sourceInfo = node.getSourceInfo();
115: description = node.toString();
116: } catch (Throwable e) {
117: // ignore any exceptions
118: if (description == null) {
119: description = "<source info not available>";
120: }
121: } finally {
122: pendingICE.set(null);
123: }
124: addNode(className, description, sourceInfo);
125: }
126:
127: /**
128: * Adds information about a a node to the end of the node trace. This is
129: * similar to how a stack trace works.
130: */
131: public void addNode(String className, String description,
132: SourceInfo sourceInfo) {
133: nodeTrace.add(new NodeInfo(className, description, sourceInfo));
134: }
135:
136: /**
137: * Returns a list of nodes that were being processed when this exception was
138: * thrown. The list reflects the parent-child relationships of the AST and is
139: * is in order from children to parents. The first element of the returned
140: * list is the node that was most specifically being visited when the
141: * exception was thrown.
142: */
143: public List<NodeInfo> getNodeTrace() {
144: return nodeTrace;
145: }
146:
147: }
|