package polyglot.ext.jl.ast;
import polyglot.ast.*;
import polyglot.visit.*;
import polyglot.types.*;
import polyglot.util.*;
import java.util.*;
/**
* A <code>Conditional</code> is a representation of a Java ternary
* expression. That is, <code>(cond ? consequent : alternative)</code>.
*/
public class Conditional_c extends Expr_c implements Conditional
{
protected Expr cond;
protected Expr consequent;
protected Expr alternative;
public Conditional_c(Position pos, Expr cond, Expr consequent, Expr alternative) {
super(pos);
this.cond = cond;
this.consequent = consequent;
this.alternative = alternative;
}
/** Get the precedence of the expression. */
public Precedence precedence() {
return Precedence.CONDITIONAL;
}
/** Get the conditional of the expression. */
public Expr cond() {
return this.cond;
}
/** Set the conditional of the expression. */
public Conditional cond(Expr cond) {
Conditional_c n = (Conditional_c) copy();
n.cond = cond;
return n;
}
/** Get the consequent of the expression. */
public Expr consequent() {
return this.consequent;
}
/** Set the consequent of the expression. */
public Conditional consequent(Expr consequent) {
Conditional_c n = (Conditional_c) copy();
n.consequent = consequent;
return n;
}
/** Get the alternative of the expression. */
public Expr alternative() {
return this.alternative;
}
/** Set the alternative of the expression. */
public Conditional alternative(Expr alternative) {
Conditional_c n = (Conditional_c) copy();
n.alternative = alternative;
return n;
}
/** Reconstruct the expression. */
protected Conditional_c reconstruct(Expr cond, Expr consequent, Expr alternative) {
if (cond != this.cond || consequent != this.consequent || alternative != this.alternative) {
Conditional_c n = (Conditional_c) copy();
n.cond = cond;
n.consequent = consequent;
n.alternative = alternative;
return n;
}
return this;
}
/** Visit the children of the expression. */
public Node visitChildren(NodeVisitor v) {
Expr cond = (Expr) visitChild(this.cond, v);
Expr consequent = (Expr) visitChild(this.consequent, v);
Expr alternative = (Expr) visitChild(this.alternative, v);
return reconstruct(cond, consequent, alternative);
}
/** Type check the expression. */
public Node typeCheck(TypeChecker tc) throws SemanticException {
TypeSystem ts = tc.typeSystem();
if (! ts.equals(cond.type(), ts.Boolean())) {
throw new SemanticException(
"Condition of ternary expression must be of type boolean.",
cond.position());
}
Expr e1 = consequent;
Expr e2 = alternative;
Type t1 = e1.type();
Type t2 = e2.type();
// From the JLS, section:
// If the second and third operands have the same type (which may be
// the null type), then that is the type of the conditional expression.
if (ts.equals(t1, t2)) {
return type(t1);
}
// Otherwise, if the second and third operands have numeric type, then
// there are several cases:
if (t1.isNumeric() && t2.isNumeric()) {
// - If one of the operands is of type byte and the other is of
// type short, then the type of the conditional expression is
// short.
if (t1.isByte() && t2.isShort() || t1.isShort() && t2.isByte()) {
return type(ts.Short());
}
// - If one of the operands is of type T where T is byte, short, or
// char, and the other operand is a constant expression of type int
// whose value is representable in type T, then the type of the
// conditional expression is T.
if (t1.isIntOrLess() &&
t2.isInt() &&
ts.numericConversionValid(t1, e2.constantValue())) {
return type(t1);
}
if (t2.isIntOrLess() &&
t1.isInt() &&
ts.numericConversionValid(t2, e1.constantValue())) {
return type(t2);
}
// - Otherwise, binary numeric promotion (�5.6.2) is applied to the
// operand types, and the type of the conditional expression is the
// promoted type of the second and third operands. Note that binary
// numeric promotion performs value set conversion (�5.1.8).
return type(ts.promote(t1, t2));
}
// If one of the second and third operands is of the null type and the
// type of the other is a reference type, then the type of the
// conditional expression is that reference type.
if (t1.isNull() && t2.isReference()) return type(t2);
if (t2.isNull() && t1.isReference()) return type(t1);
// If the second and third operands are of different reference types,
// then it must be possible to convert one of the types to the other
// type (call this latter type T) by assignment conversion (�5.2); the
// type of the conditional expression is T. It is a compile-time error
// if neither type is assignment compatible with the other type.
if (t1.isReference() && t2.isReference()) {
if (ts.isImplicitCastValid(t1, t2)) {
return type(t2);
}
if (ts.isImplicitCastValid(t2, t1)) {
return type(t1);
}
}
throw new SemanticException(
"Could not find a type for ternary conditional expression.",
position());
}
public Type childExpectedType(Expr child, AscriptionVisitor av) {
TypeSystem ts = av.typeSystem();
if (child == cond) {
return ts.Boolean();
}
if (child == consequent || child == alternative) {
return type();
}
return child.type();
}
public String toString() {
return cond + " ? " + consequent + " : " + alternative;
}
/** Write the expression to an output file. */
public void prettyPrint(CodeWriter w, PrettyPrinter tr)
{
printSubExpr(cond, false, w, tr);
w.write(" ? ");
printSubExpr(consequent, false, w, tr);
w.write(" : ");
printSubExpr(alternative, false, w, tr);
}
public Term entry() {
return cond.entry();
}
public List acceptCFG(CFGBuilder v, List succs) {
v.visitCFG(cond, FlowGraph.EDGE_KEY_TRUE, consequent.entry(),
FlowGraph.EDGE_KEY_FALSE, alternative.entry());
v.visitCFG(consequent, this);
v.visitCFG(alternative, this);
return succs;
}
public boolean isConstant() {
return cond.isConstant() && consequent.isConstant() && alternative.isConstant();
}
public Object constantValue() {
Object cond_ = cond.constantValue();
Object then_ = consequent.constantValue();
Object else_ = alternative.constantValue();
if (cond_ instanceof Boolean && then_ != null && else_ != null) {
boolean c = ((Boolean) cond_).booleanValue();
if (c) {
return then_;
}
else {
return else_;
}
}
return null;
}
}