package polyglot.visit; import polyglot.ast.*; import java.util.*; /** * The <code>CodeCleaner</code> runs over the AST and performs some trivial * dead code elimination, while flattening blocks wherever possible. **/ public class CodeCleaner extends NodeVisitor { protected NodeFactory nf; protected AlphaRenamer alphaRen; /** * Creates a visitor for cleaning code. * * @param nf The node factory to be used when generating new nodes. **/ public CodeCleaner(NodeFactory nf) { this.nf = nf; this.alphaRen = new AlphaRenamer(nf); } public Node leave( Node old, Node n, NodeVisitor v ) { if ( !(n instanceof Block || n instanceof Labeled) ) { return n; } // If we have a labeled block consisting of just one statement, then // flatten the block and label the statement instead. We also flatten // labeled blocks when there is no reference to the label within the // block. if ( n instanceof Labeled ) { Labeled l = (Labeled)n; if ( !(l.statement() instanceof Block) ) { return n; } Block b = (Block)l.statement(); if ( b.statements().size() != 1 ) { if ( labelRefs(b).contains(l.label()) ) { return n; } // There's no reference to the label within the block, so flatten and // clean up dead code. return nf.Block( b.position(), clean(flattenBlock(b)) ); } // Alpha-rename local decls in the block that we're flattening. b = (Block)b.visit(alphaRen); return nf.Labeled( l.position(), l.label(), (Stmt)b.statements().get(0) ); } // Flatten any blocks that may be contained in this one, and clean up dead // code. Block b = (Block)n; List stmtList = clean(flattenBlock(b)); if ( b instanceof SwitchBlock ) { return nf.SwitchBlock( b.position(), stmtList ); } return nf.Block( b.position(), stmtList ); } /** * Turns a Block into a list of Stmts. **/ protected List flattenBlock( Block b ) { List stmtList = new LinkedList(); for ( Iterator it = b.statements().iterator(); it.hasNext(); ) { Stmt stmt = (Stmt)it.next(); if ( stmt instanceof Block ) { // Alpha-rename local decls in the block that we're flattening. stmt = (Stmt)stmt.visit(alphaRen); stmtList.addAll( ((Block)stmt).statements() ); } else { stmtList.add( stmt ); } } return stmtList; } /** * Performs some trivial dead code elimination on a list of statements. **/ protected List clean( List l ) { List stmtList = new LinkedList(); for ( Iterator it = l.iterator(); it.hasNext(); ) { Stmt stmt = (Stmt)it.next(); stmtList.add( stmt ); if ( stmt instanceof Branch || stmt instanceof Return || stmt instanceof Throw ) { return stmtList; } } return l; } /** * Traverses a Block and determines the set of label references. **/ protected Set labelRefs( Block b ) { final Set result = new HashSet(); b.visit( new NodeVisitor() { public Node leave( Node old, Node n, NodeVisitor v ) { if ( n instanceof Branch ) { result.add( ((Branch)n).label() ); } return n; } } ); return result; } }