KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > polyglot > visit > CodeCleaner


1 package polyglot.visit;
2
3 import polyglot.ast.*;
4 import java.util.*;
5
6 /**
7  * The <code>CodeCleaner</code> runs over the AST and performs some trivial
8  * dead code elimination, while flattening blocks wherever possible.
9  **/

10 public class CodeCleaner extends NodeVisitor {
11
12   protected NodeFactory nf;
13   protected AlphaRenamer alphaRen;
14
15   /**
16    * Creates a visitor for cleaning code.
17    *
18    * @param nf The node factory to be used when generating new nodes.
19    **/

20   public CodeCleaner(NodeFactory nf) {
21     this.nf = nf;
22     this.alphaRen = new AlphaRenamer(nf);
23   }
24
25   public Node leave( Node old, Node n, NodeVisitor v ) {
26     if ( !(n instanceof Block || n instanceof Labeled) ) {
27       return n;
28     }
29
30     // If we have a labeled block consisting of just one statement, then
31
// flatten the block and label the statement instead. We also flatten
32
// labeled blocks when there is no reference to the label within the
33
// block.
34
if ( n instanceof Labeled ) {
35       Labeled l = (Labeled)n;
36       if ( !(l.statement() instanceof Block) ) {
37         return n;
38       }
39
40       Block b = (Block)l.statement();
41       if ( b.statements().size() != 1 ) {
42     if ( labelRefs(b).contains(l.label()) ) {
43       return n;
44     }
45
46     // There's no reference to the label within the block, so flatten and
47
// clean up dead code.
48
return nf.Block( b.position(), clean(flattenBlock(b)) );
49       }
50
51       // Alpha-rename local decls in the block that we're flattening.
52
b = (Block)b.visit(alphaRen);
53       return nf.Labeled( l.position(), l.label(),
54                          (Stmt)b.statements().get(0) );
55     }
56
57     // Flatten any blocks that may be contained in this one, and clean up dead
58
// code.
59
Block b = (Block)n;
60     List stmtList = clean(flattenBlock(b));
61
62     if ( b instanceof SwitchBlock ) {
63       return nf.SwitchBlock( b.position(), stmtList );
64     }
65
66     return nf.Block( b.position(), stmtList );
67   }
68
69   /**
70    * Turns a Block into a list of Stmts.
71    **/

72   protected List flattenBlock( Block b ) {
73     List stmtList = new LinkedList();
74     for ( Iterator it = b.statements().iterator(); it.hasNext(); ) {
75       Stmt stmt = (Stmt)it.next();
76       if ( stmt instanceof Block ) {
77     // Alpha-rename local decls in the block that we're flattening.
78
stmt = (Stmt)stmt.visit(alphaRen);
79         stmtList.addAll( ((Block)stmt).statements() );
80       } else {
81         stmtList.add( stmt );
82       }
83     }
84
85     return stmtList;
86   }
87
88   /**
89    * Performs some trivial dead code elimination on a list of statements.
90    **/

91   protected List clean( List l ) {
92     List stmtList = new LinkedList();
93     for ( Iterator it = l.iterator(); it.hasNext(); ) {
94       Stmt stmt = (Stmt)it.next();
95       stmtList.add( stmt );
96
97       if ( stmt instanceof Branch || stmt instanceof Return
98            || stmt instanceof Throw ) {
99     return stmtList;
100       }
101     }
102
103     return l;
104   }
105
106   /**
107    * Traverses a Block and determines the set of label references.
108    **/

109   protected Set labelRefs( Block b ) {
110     final Set result = new HashSet();
111     b.visit( new NodeVisitor() {
112     public Node leave( Node old, Node n, NodeVisitor v ) {
113       if ( n instanceof Branch ) {
114         result.add( ((Branch)n).label() );
115       }
116
117       return n;
118     }
119       } );
120
121     return result;
122   }
123 }
124
Popular Tags