package de.gaalop.cfg;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import de.gaalop.dfg.Expression;
/**
* This abstract class serves as the base class for all control flow nodes in a control flow graph.
* <p/>
* Please note that all implementing classes should provide a meaningful implementation of {@link Object#toString()},
* {@link Object#hashCode()} and {@link Object#equals(Object)}.
*
* @author Sebastian Hartte
* @version 1.0
* @see ControlFlowGraph
* @since 1.0
*/
public abstract class Node {
/** All predecessors of this node. */
private Set<Node> predecessors = new HashSet<Node>();
/** A reference to the graph that contains this node. */
private final ControlFlowGraph graph;
/**
* Constructs a new control flow node.
*
* @param graph The graph that will contain this node.
*/
public Node(ControlFlowGraph graph) {
this.graph = graph;
}
/**
* Gets the control flow graph this node belongs to.
*
* @return The control flow graph linked to this node.
*/
public ControlFlowGraph getGraph() {
return graph;
}
/**
* This method must be implemented by every concrete subclass. It should call a visit method in ControlFlowVisitor whose only
* parameter has the concrete type of the object calling the method.
* <p/>
* Please see the Visitor Pattern for more detail.
*
* @param visitor The visitor object that the visit method will be called on.
*/
public abstract void accept(ControlFlowVisitor visitor);
/**
* Returns all nodes that have this node as their successor.
*
* @return An unmodifiable set of nodes that contains all predecessors of this node.
*/
public Set<Node> getPredecessors() {
return Collections.unmodifiableSet(predecessors);
}
/**
* Adds a predecessor to this node.
* <p/>
* This method may throw an UnsupportedOperationException if the subclass does not allow predecessors. This is only the case
* if this node is the start node.
*
* @param node The new predecessor for this node.
* @see UnsupportedOperationException
*/
public void addPredecessor(Node node) {
predecessors.add(node);
}
/**
* This method removes predecessors from this node.
* <p/>
* This method may throw an UnsupportedOperationException if the implementing node must not have any predecessors. This is
* only the case if this node is the start node.
*
* @param node The node that should be removed from the predecessors of this node.
*/
public void removePredecessor(Node node) {
predecessors.remove(node);
}
/**
* Replaces the connection from this node to oldSuccessor with a connection from this node to newSuccessor if it exists.
* <p/>
* This method can be used to insert or remove nodes in a control flow graph.
*
* @param oldSuccessor A node that is currently a successor of this node.
* @param newSuccessor A node that should become a successor of this node instead of <code>oldSuccessor</code>.
*/
public abstract void replaceSuccessor(Node oldSuccessor, Node newSuccessor);
/**
* Classes that store an {@link Expression} attribute should implement this method to allow recursive replacement of
* expressions. This implementation throws an {@link UnsupportedOperationException} by default.
*
* @param old expression to be replaced.
* @param newExpression
*/
public void replaceExpression(Expression old, Expression newExpression) {
throw new UnsupportedOperationException("Cannot replace an expression. This node type (" + toString()
+ ") does not have an expression attribute.");
}
/**
* Inserts another node right before this node.
* <p/>
* The new node is added as a successor of all predecessors of this node and this node is set as the successor of the new
* node.
*
* @param newNode The node that should be inserted.
*/
public void insertBefore(SequentialNode newNode) {
newNode.setSuccessor(this);
Set<Node> predecessors = new HashSet<Node>(getPredecessors());
for (Node predecessor : predecessors) {
predecessor.replaceSuccessor(this, newNode);
}
predecessors.clear(); // previous predecessors are no predecessors anymore
addPredecessor(newNode);
}
}