DumpFacade.java
001 /**
002  * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
003  */
004 package net.sourceforge.pmd.lang.ecmascript.ast;
005 
006 import java.io.IOException;
007 import java.io.PrintWriter;
008 import java.io.Writer;
009 import java.util.ArrayList;
010 import java.util.List;
011 
012 public class DumpFacade {
013 
014     private PrintWriter writer;
015     private boolean recurse;
016 
017     public void initializeWith(Writer writer, String prefix, boolean recurse, EcmascriptNode node) {
018   this.writer = (writer instanceof PrintWriter) ? (PrintWriter) writer : new PrintWriter(writer);
019   this.recurse = recurse;
020   this.dump(node, prefix);
021   try {
022       writer.flush();
023   } catch (IOException e) {
024       throw new RuntimeException("Problem flushing PrintWriter.", e);
025   }
026     }
027 
028     public Object visit(EcmascriptNode node, Object data) {
029   dump(node, (String) data);
030   if (recurse) {
031       for (int i = 0; i < node.jjtGetNumChildren(); i++) {
032     visit((EcmascriptNode) node.jjtGetChild(i), data + " ");
033       }
034       return data;
035   } else {
036       return data;
037   }
038     }
039 
040     private void dump(EcmascriptNode node, String prefix) {
041   //
042   // Dump format is generally composed of the following items...
043   //
044 
045   // 1) Dump prefix
046   writer.print(prefix);
047 
048   // 2) JJT Name of the Node
049   writer.print(node.toString());
050 
051   //
052   // If there are any additional details, then:
053   // 1) A colon
054   // 2) The Node.getImage() if it is non-empty
055   // 3) Extras in parentheses
056   //
057 
058   // Standard image handling
059   String image = node.getImage();
060 
061   // Special image handling (e.g. Nodes with normally null images)
062   image = escape(image);
063 
064   // Extras
065   List<String> extras = new ArrayList<String>();
066 
067   // Standard DestructuringNode extras
068   if (node instanceof DestructuringNode) {
069       if (((DestructuringNode) node).isDestructuring()) {
070     extras.add("destructuring");
071       }
072   }
073 
074   // Other extras
075   if (node instanceof ASTArrayComprehension) {
076       if (((ASTArrayComprehension) node).hasFilter()) {
077     extras.add("has filter");
078       }
079   } else if (node instanceof ASTBreakStatement) {
080       if (((ASTBreakStatement) node).hasLabel()) {
081     extras.add("has label");
082       }
083   } else if (node instanceof ASTCatchClause) {
084       if (((ASTCatchClause) node).isIf()) {
085     extras.add("if");
086       }
087   } else if (node instanceof ASTContinueStatement) {
088       if (((ASTContinueStatement) node).hasLabel()) {
089     extras.add("has label");
090       }
091   } else if (node instanceof ASTExpressionStatement) {
092       if (((ASTExpressionStatement) node).hasResult()) {
093     extras.add("has result");
094       }
095   } else if (node instanceof ASTForInLoop) {
096       if (((ASTForInLoop) node).isForEach()) {
097     extras.add("for each");
098       }
099   } else if (node instanceof ASTFunctionCall) {
100       if (((ASTFunctionCall) node).hasArguments()) {
101     extras.add("has arguments");
102       }
103   } else if (node instanceof ASTFunctionNode) {
104       if (((ASTFunctionNode) node).isClosure()) {
105     extras.add("closure");
106       }
107       if (((ASTFunctionNode) node).isGetter()) {
108     extras.add("getter");
109       }
110       if (((ASTFunctionNode) node).isSetter()) {
111     extras.add("setter");
112       }
113   } else if (node instanceof ASTIfStatement) {
114       if (((ASTIfStatement) node).hasElse()) {
115     extras.add("has else");
116       }
117   } else if (node instanceof ASTKeywordLiteral) {
118       if (((ASTKeywordLiteral) node).isBoolean()) {
119     extras.add("boolean");
120       }
121   } else if (node instanceof ASTLetNode) {
122       if (((ASTLetNode) node).hasBody()) {
123     extras.add("has body");
124       }
125   } else if (node instanceof ASTName) {
126       if (((ASTName) node).isLocalName()) {
127     extras.add("local");
128       }
129       if (((ASTName) node).isGlobalName()) {
130     extras.add("global");
131       }
132   } else if (node instanceof ASTNewExpression) {
133       if (((ASTNewExpression) node).hasArguments()) {
134     extras.add("has arguments");
135       }
136       if (((ASTNewExpression) node).hasInitializer()) {
137     extras.add("has initializer");
138       }
139   } else if (node instanceof ASTNumberLiteral) {
140       extras.add("Number=" + ((ASTNumberLiteral) node).getNumber());
141       extras.add("NormalizedImage=" + ((ASTNumberLiteral) node).getNormalizedImage());
142   } else if (node instanceof ASTObjectProperty) {
143       if (((ASTObjectProperty) node).isGetter()) {
144     extras.add("getter");
145       }
146       if (((ASTObjectProperty) node).isSetter()) {
147     extras.add("setter");
148       }
149   } else if (node instanceof ASTRegExpLiteral) {
150       extras.add("Flags=" + ((ASTRegExpLiteral) node).getFlags());
151   } else if (node instanceof ASTReturnStatement) {
152       if (((ASTReturnStatement) node).hasResult()) {
153     extras.add("has result");
154       }
155   } else if (node instanceof ASTStringLiteral) {
156       if (((ASTStringLiteral) node).isSingleQuoted()) {
157     extras.add("single quoted");
158       }
159       if (((ASTStringLiteral) node).isDoubleQuoted()) {
160     extras.add("double quoted");
161       }
162   } else if (node instanceof ASTSwitchCase) {
163       if (((ASTSwitchCase) node).isDefault()) {
164     extras.add("default");
165       }
166   } else if (node instanceof ASTTryStatement) {
167       if (((ASTTryStatement) node).isCatch()) {
168     extras.add("catch");
169       }
170       if (((ASTTryStatement) node).isFinally()) {
171     extras.add("finally");
172       }
173   } else if (node instanceof ASTUnaryExpression) {
174       if (((ASTUnaryExpression) node).isPrefix()) {
175     extras.add("prefix");
176       }
177       if (((ASTUnaryExpression) node).isPostfix()) {
178     extras.add("postfix");
179       }
180   }
181 
182   // Standard EcmascriptNode extras
183   if (node.hasSideEffects()) {
184       extras.add("has side effects");
185   }
186 
187   // Output image and extras
188   if (image != null || !extras.isEmpty()) {
189       writer.print(":");
190       if (image != null) {
191     writer.print(image);
192       }
193       for (String extra : extras) {
194     writer.print("(");
195     writer.print(extra);
196     writer.print(")");
197       }
198   }
199 
200   writer.println();
201     }
202 
203     private static String escape(Object o) {
204   // Replace some whitespace characters so they are visually apparent.
205   if (o == null) {
206       return null;
207   }
208   String s = String.valueOf(o);
209   s = s.replace("\n", "\\n");
210   s = s.replace("\r", "\\r");
211   s = s.replace("\t", "\\t");
212   return s;
213     }
214 }