Operation op = (Operation) e;
List<? extends Expression> operands = op.children();
Expression[] newOperands = null;
int n = operands.size();
for (int i = 0; i < n; ++i) {
Expression operand = operands.get(i);
Expression newOperand = optimizeExpressionFlow(operand);
if (operand != newOperand) {
if (newOperands == null) {
newOperands = operands.toArray(new Expression[n]);
}
newOperands[i] = newOperand;
}
}
Operator oper = op.getOperator();
FilePosition pos = e.getFilePosition();
if (oper != Operator.TERNARY) {
return newOperands == null ? e : Operation.create(pos, oper, newOperands);
}
// (c ? x,z : y,z) -> (c ? x:y),z
Expression[] ternaryOperands = newOperands != null
? newOperands : operands.toArray(new Expression[3]);
Expression c = ternaryOperands[0];
Expression x = ternaryOperands[1];
Expression y = ternaryOperands[2];
while (Operation.is(c, Operator.NOT)) {
c = ((Operation) c).children().get(0);
Expression t = x;
x = y;
y = t;
}
if (ParseTreeNodes.deepEquals(x, y)) {
if (c.simplifyForSideEffect() == null) { return x; }
return commaOp(pos, c, x);
}
if (isSimple(c)) {
// If a reference fails with an exception because it is undefined, then
// control would never reach the second identical expression.
if (ParseTreeNodes.deepEquals(c, x)) {
// (c ? c : y) -> c || y if c not side effecting
return Operation.create(pos, Operator.LOGICAL_OR, c, y);
} else if (ParseTreeNodes.deepEquals(c, y)) {
// (c ? x : c) -> c && x if c not side effecting
return Operation.create(pos, Operator.LOGICAL_AND, c, x);
}
}
// TODO(mikesamuel): if c is simple and not a global reference, optimize
// out he common head as well.
CommaCommonalities opt = commaCommonalities(x, y);
if (opt != null) {
// Both reduced sides can't be null since we checked above whether
// x and y are structurally identical.
if (opt.aReduced == null) {
// (c ? z: y,z) -> (c || y),z
return commaOp(
pos,
Operation.createInfix(Operator.LOGICAL_OR, c, opt.bReduced),
opt.commonTail);
} else if (opt.bReduced == null) {
// (c ? x,z : z) -> (c && x),z
return commaOp(
pos,
Operation.createInfix(Operator.LOGICAL_AND, c, opt.aReduced),
opt.commonTail);
} else {
// (c ? x,z : y,z) -> (c ? x : y),z
return commaOp(
pos,
optimizeExpressionFlow(
Operation.createTernary(c, opt.aReduced, opt.bReduced)),
opt.commonTail);
}
}
ternaryOperands[0] = c;
ternaryOperands[1] = x;
ternaryOperands[2] = y;
if (x instanceof Operation && y instanceof Operation) {
Operation xop = (Operation) x;
Operation yop = (Operation) y;
Operator xoper = xop.getOperator();
if (xoper == yop.getOperator()) {
List<? extends Expression> xoperands = xop.children();
List<? extends Expression> yoperands = yop.children();
int nOperands = xoperands.size();
if (nOperands == yoperands.size()) {
Expression xoperand0 = xoperands.get(0);
// We can often pull the rightmost operand out since it would be
// evaluated last regardless.
if (nOperands == 2
&& ParseTreeNodes.deepEquals(xoperands.get(1), yoperands.get(1))
&& xoper.getCategory() != OperatorCategory.ASSIGNMENT