package de.gaalop.cfg;
import de.gaalop.dfg.Expression;
/**
* Models a node for if-then(-else) statements. It consists of an {@link Expression} modeling the condition to be
* evaluated, the first statement to be executed for the positive case and the first statement to be executed for the
* negative case. The negative part is optional and is supposed to be represented by a {@link BlockEndNode} when there
* is only a positive part. The next statement in the control flow graph to be executed is implicitly determined by this
* node's successor.
*
* @author Christian Schwinn
*
*/
public class IfThenElseNode extends SequentialNode {
/** Evaluation condition. */
private Expression condition;
/** First statement to be evaluated when condition is true. */
private SequentialNode positive;
/** First statement to be evaluated when condition is false. */
private SequentialNode negative;
/** Whether this node represents the special case of an else-if part. */
private boolean elseif;
public IfThenElseNode(ControlFlowGraph graph, Expression condition) {
super(graph);
this.condition = condition;
}
/**
* @return the evaluation condition
*/
public Expression getCondition() {
return condition;
}
/**
* @return the first node to be executed when <i>condition</i> evaluates to true
*/
public SequentialNode getPositive() {
return positive;
}
/**
* Sets the property to be an else-if part for this node.
*
* @param elseif whether this node is an else-if part.
*/
public void setElseIf(boolean elseif) {
this.elseif = elseif;
}
/**
* Returns the else-if property of this node.
*
* @return whether this node is an else-if part.
*/
public boolean isElseIf() {
return elseif;
}
/**
* Sets the first node to be executed when the evaluation condition evaluates to true.
*
* @param first control flow node to be executed in the positive case
*/
public void setPositive(SequentialNode positive) {
this.positive = positive;
}
/**
* @return the first node to be executed when <i>condition</i> evaluates to false. If there is no negative part,
* this function returns a {@link BlockEndNode}.
*/
public SequentialNode getNegative() {
return negative;
}
/**
* Sets the first node to be executed when the evaluation condition evaluates to false.
*
* @param first control flow nodes to be executed in the negative case. Should be a {@link BlockEndNode} in case of
* a non-existent else part.
*/
public void setNegative(SequentialNode negative) {
this.negative = negative;
}
@Override
public void accept(ControlFlowVisitor visitor) {
visitor.visit(this);
}
@Override
public void replaceSuccessor(Node oldSuccessor, Node newSuccessor) {
if (oldSuccessor == positive) {
newSuccessor.removePredecessor(oldSuccessor);
newSuccessor.addPredecessor(this);
// cast is safe since branch of if-then-else cannot be the end node
setPositive((SequentialNode) newSuccessor);
} else if (oldSuccessor == negative) {
newSuccessor.removePredecessor(oldSuccessor);
newSuccessor.addPredecessor(this);
// cast is safe since branch of if-then-else cannot be the end node
setNegative((SequentialNode) newSuccessor);
} else {
super.replaceSuccessor(oldSuccessor, newSuccessor);
}
}
@Override
public void replaceExpression(Expression old, Expression newExpression) {
if (condition == old) {
condition = newExpression;
} else {
condition.replaceExpression(old, newExpression);
}
replaceSubtree(positive, old, newExpression);
if (negative != null) {
replaceSubtree(negative, old, newExpression);
}
}
private void replaceSubtree(Node root, Expression old, Expression newExpression) {
if (root instanceof BlockEndNode || root instanceof EndNode) {
return;
} else if (root instanceof SequentialNode) {
root.replaceExpression(old, newExpression);
replaceSubtree(((SequentialNode) root).getSuccessor(), old, newExpression);
}
}
@Override
public IfThenElseNode copyElements() {
IfThenElseNode copy = new IfThenElseNode(getGraph(), condition.copy());
copy.elseif = elseif;
SequentialNode newPositive = positive.copy();
newPositive.removePredecessor(this);
newPositive.addPredecessor(copy);
copy.setPositive(newPositive);
copySubtree(newPositive, copy);
SequentialNode newNegative = negative.copy();
newNegative.removePredecessor(this);
newNegative.addPredecessor(copy);
copy.setNegative(newNegative);
copySubtree(newNegative, copy);
return copy;
}
private void copySubtree(SequentialNode root, SequentialNode newBase) {
if (root instanceof BlockEndNode) {
((BlockEndNode) root).updateBase(newBase);
return;
} else if (root.getSuccessor() instanceof SequentialNode) {
SequentialNode successor = (SequentialNode) root.getSuccessor();
SequentialNode newSuccessor = successor.copy();
root.replaceSuccessor(successor, newSuccessor);
copySubtree(newSuccessor, newBase);
}
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("if(" + condition + ")");
sb.append(",then={");
SequentialNode current = positive;
while (!(current instanceof BlockEndNode)) {
sb.append(current);
sb.append(';');
current = (SequentialNode) current.getSuccessor();
}
sb.append("}");
current = negative;
if (!(current instanceof BlockEndNode)) {
sb.append(",else={");
while (!(current instanceof BlockEndNode)) {
sb.append(current);
sb.append(';');
current = (SequentialNode) current.getSuccessor();
}
sb.append("}");
}
return sb.toString();
}
}