package polyglot.ext.jl.ast;
import polyglot.ast.*;
import polyglot.types.*;
import polyglot.visit.*;
import polyglot.util.*;
import java.util.*;
/**
* A <code>Case</code> is a representation of a Java <code>case</code>
* statement. It can only be contained in a <code>Switch</code>.
*/
public class Case_c extends Stmt_c implements Case
{
protected Expr expr;
protected long value;
public Case_c(Position pos, Expr expr) {
super(pos);
this.expr = expr;
}
/** Returns true iff this is the default case. */
public boolean isDefault() {
return this.expr == null;
}
/**
* Get the case label. This must should a constant expression.
* The case label is null for the <code>default</code> case.
*/
public Expr expr() {
return this.expr;
}
/** Set the case label. This must should a constant expression, or null. */
public Case expr(Expr expr) {
Case_c n = (Case_c) copy();
n.expr = expr;
return n;
}
/**
* Returns the value of the case label. This value is only valid
* after type-checking.
*/
public long value() {
return this.value;
}
/** Set the value of the case label. */
public Case value(long value) {
Case_c n = (Case_c) copy();
n.value = value;
return n;
}
/** Reconstruct the statement. */
protected Case_c reconstruct(Expr expr) {
if (expr != this.expr) {
Case_c n = (Case_c) copy();
n.expr = expr;
return n;
}
return this;
}
/** Visit the children of the statement. */
public Node visitChildren(NodeVisitor v) {
Expr expr = (Expr) visitChild(this.expr, v);
return reconstruct(expr);
}
/** Type check the statement. */
public Node typeCheck(TypeChecker tc) throws SemanticException {
if (expr == null) {
return this;
}
TypeSystem ts = tc.typeSystem();
if (! ts.isImplicitCastValid(expr.type(), ts.Int())) {
throw new SemanticException(
"Case label must be an byte, char, short, or int.",
position());
}
Object o = null;
if (expr instanceof Field) {
FieldInstance fi = ((Field) expr).fieldInstance();
if (fi == null) {
throw new InternalCompilerError(
"Undefined FieldInstance after type-checking.");
}
if (! fi.isConstant()) {
throw new SemanticException("Case label must be an integral constant.",
position());
}
o = fi.constantValue();
}
else if (expr instanceof Local) {
LocalInstance li = ((Local) expr).localInstance();
if (li == null) {
throw new InternalCompilerError(
"Undefined LocalInstance after type-checking.");
}
if (! li.isConstant()) {
/* FIXME: isConstant() is incorrect
throw new SemanticException("Case label must be an integral constant.",
position());
*/
return this;
}
o = li.constantValue();
}
else {
o = expr.constantValue();
}
if (o instanceof Number && ! (o instanceof Long) &&
! (o instanceof Float) && ! (o instanceof Double)) {
return value(((Number) o).longValue());
}
else if (o instanceof Character) {
return value(((Character) o).charValue());
}
throw new SemanticException("Case label must be an integral constant.",
position());
}
public Type childExpectedType(Expr child, AscriptionVisitor av) {
TypeSystem ts = av.typeSystem();
if (child == expr) {
return ts.Int();
}
return child.type();
}
public String toString() {
if (expr == null) {
return "default:";
}
else {
return "case " + expr + ":";
}
}
/** Write the statement to an output file. */
public void prettyPrint(CodeWriter w, PrettyPrinter tr) {
if (expr == null) {
w.write("default:");
}
else {
w.write("case ");
print(expr, w, tr);
w.write(":");
}
}
public Term entry() {
if (expr != null) return expr;
return this;
}
public List acceptCFG(CFGBuilder v, List succs) {
if (expr != null) {
v.visitCFG(expr, this);
}
return succs;
}
}