/**
* This file is part of Erjang - A JVM-based Erlang VM
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
package erjang.beam.analysis;
import erjang.beam.BeamExceptionHandler;
import erjang.ErlangException;
import java.util.Set;
import java.util.HashSet;
import java.util.List;
import java.util.ArrayList;
/* Representation of the stack of exception handlers active at a given
* program point.
* 'null' is the end of the stack chain.
*/
public class ExceptionHandler implements BeamExceptionHandler {
/** Special value, for use in exception handler set. */
public static final BeamExceptionHandler NULL = new BeamExceptionHandler() {
public int getHandlerLabel() {throw new InternalError();}
public BeamExceptionHandler getParent() {throw new InternalError();}
public String toString() {return "NULL";}
};
private final int handlerLabel;
private final ExceptionHandler parent;
public ExceptionHandler(int handlerLabel, ExceptionHandler parent) {
this.handlerLabel = handlerLabel;
this.parent = parent;
}
public int getHandlerLabel() {return handlerLabel;}
public ExceptionHandler getParent() {return parent;}
public List<BeamExceptionHandler> ambiguousities() {return null;}
public static ExceptionHandler push(ExceptionHandler org, int newHandlerLabel) {
assert(! (org instanceof Ambiguous));
return new ExceptionHandler(newHandlerLabel, org);
}
public static ExceptionHandler pop(ExceptionHandler org) {
if (org==null)
throw new IllegalArgumentException("Exception handler structure in beam code is not sound");
assert(! (org instanceof Ambiguous));
return org.parent;
}
public static ExceptionHandler merge(ExceptionHandler e1, ExceptionHandler e2) throws ErlangException {
// Simple cases first:
if (e1 == e2) return e1;
if (e1 == null || e2 == null ||
e1.handlerLabel != e2.handlerLabel)
throw new IllegalArgumentException("Exception handler structure in beam code is not sound");
// 'this' and 'other' are not null, and labels are known to match.
// Compare parents:
ExceptionHandler mergedParent = merge(e1.parent, e2.parent);
if (mergedParent == e1.parent) return e1; // Save memory if possible.
if (mergedParent == e2.parent) return e2; // Save memory if possible.
return new ExceptionHandler(e1.handlerLabel, mergedParent);
}
public boolean equals(Object other) {
return other instanceof ExceptionHandler &&
equals((ExceptionHandler) other);
}
public boolean equals(ExceptionHandler other) {
return equals(this,other);
}
public static boolean equals(ExceptionHandler e1, ExceptionHandler e2) {
if (e1==e2) return true;
if (e1==null || e2==null) return false;
if (e1.handlerLabel != e2.handlerLabel) return false;
if (e1 instanceof Ambiguous && e2 instanceof Ambiguous) {
Ambiguous a1 = (Ambiguous) e1;
Ambiguous a2 = (Ambiguous) e2;
return a1.exhs.equals(a2.exhs);
}
if (e1 instanceof Ambiguous || e2 instanceof Ambiguous)
return false;
return equals(e1.parent, e2.parent);
}
public int hashCode() {
return handlerLabel;
}
public int compareTo(Object other) {
if (! (other instanceof ExceptionHandler)) return 1;
return compareTo((ExceptionHandler) other);
}
public int compareTo(ExceptionHandler other) {
return this.handlerLabel - other.handlerLabel;
}
public String toString() {
return "lbl" + handlerLabel + "+" +parent;
}
public static class Ambiguous extends ExceptionHandler {
final Set<BeamExceptionHandler> exhs;
public Ambiguous(ExceptionHandler src1, ExceptionHandler src2) {
super(-1, null);
exhs = new HashSet<BeamExceptionHandler>();
add_to_set(exhs, src1);
add_to_set(exhs, src2);
}
public Ambiguous(Set<BeamExceptionHandler> exhs) {
super(-1, null);
this.exhs = exhs;
}
public static Ambiguous make(ExceptionHandler src1, ExceptionHandler src2) {
HashSet<BeamExceptionHandler> exhs = new HashSet<BeamExceptionHandler>();
add_to_set(exhs, src1);
add_to_set(exhs, src2);
Ambiguous a;
if (src1 instanceof Ambiguous && exhs.equals((a=(Ambiguous)src1).exhs))
return a;
if (src2 instanceof Ambiguous && exhs.equals((a=(Ambiguous)src2).exhs))
return a;
return new Ambiguous(exhs);
}
private static void add_to_set(Set<BeamExceptionHandler> exhs,
ExceptionHandler src)
{
if (src instanceof Ambiguous)
exhs.addAll(((Ambiguous)src).exhs);
else if (src==null)
exhs.add(NULL);
else
exhs.add(src);
}
public int hashCode() {
return exhs.hashCode();
}
public List<BeamExceptionHandler> ambiguousities() {
List<BeamExceptionHandler> result = new ArrayList<BeamExceptionHandler>(exhs.size());
for (BeamExceptionHandler x: exhs)
result.add(x==NULL? null : x);
return result;
}
public String toString() {
StringBuffer res = new StringBuffer("ambi(");
for (BeamExceptionHandler e : exhs) {
res.append(e).append(" ");
}
res.append(")");
return res.toString();
}
}
}