001 /**
002 * $Id: ASTDotVisitor.java,v 1.2 2006/09/25 15:48:32 chalin Exp $
003 *
004 * @title "AST DOT file visitor"
005 * @description "Walks through an AST and outputs a dot graph format representation of that AST"
006 * @
007 */
008
009 package javafe.ast;
010
011 import java.io.Writer;
012 import java.io.FileWriter;
013 import java.io.ByteArrayOutputStream;
014 import java.io.IOException;
015 import java.io.OutputStream;
016 import javafe.util.Location;
017 import java.util.StringTokenizer;
018
019 public class ASTDotVisitor extends Visitor {
020
021 /**
022 * our means of outputting the dot representation of the AST
023 */
024 private FileWriter out = null;
025
026 /**
027 * a means of getting source text from the pretty printer
028 */
029 private ByteArrayOutputStream source_dump = null;
030
031 /**
032 * stores result of the last visit method call
033 */
034 private String visit_string = "";
035
036 /**
037 * pretty printer for extracting our source text
038 */
039 private StandardPrettyPrint printer = null;
040
041 /**
042 * Sets up the visit string for writing to a dot file with the given
043 * source text, dotId and node type. This will also reset the buffer which
044 * the pretty printer writes to.
045 */
046 private void setVisitString(String source_text, int dotId, String type) {
047 // set the string
048 visit_string = '"' + "" + dotId + " " + type + " " + source_text + '"';
049 // reset the buffer
050 source_dump.reset();
051 }
052
053 /**
054 * recurses through the tree and writes the dotfile representation of it. if
055 * parent is null this is the root of the tree. current is the node we are
056 * parsing.
057 */
058 private void writeDot(ASTNode parent, ASTNode current) {
059 // if this node is the root of the tree start the recursion otherwise make
060 // the links between this node and its parent then do the recursive call
061 // on the children
062 if(parent != null) {
063 // contains the id and type of the parent node
064 String parent_representation;
065 // contains the id and type of this node
066 String current_representation;
067 // call the visitor on parent and current and retrieve the string descriptions
068 parent.accept(this);
069 parent_representation = visit_string;
070 current.accept(this);
071 current_representation = visit_string;
072 // make the link in the file
073 try {
074 out.write(" " + parent_representation + " -> " + current_representation + "\n");
075 } catch (IOException exception) {
076 System.out.println("failed to write to file");
077 }
078 }
079 // do the recursive call on the children provided the child is an ASTNode
080 for(int count = 0; count < current.childCount(); count++) {
081 Object o = current.childAt(count);
082 if(o instanceof ASTNode) writeDot(current, (ASTNode) o);
083 }
084 }
085
086 /**
087 * constructor that takes in a compilation unit that represents a class
088 * and initalizes a filewriter in the directory escjava is called from
089 */
090 public ASTDotVisitor() {
091 // holds the value of this node so when we do recursive calls we can make
092 // the correct edges in the graph
093 //
094 // try opening the file for now throw a message out if it fails
095 try {
096 out = new FileWriter("Test.dot");
097 } catch(IOException exception) {
098 System.out.println("could not open file");
099 }
100 // init source_dump and printer
101 source_dump = new ByteArrayOutputStream();
102 printer = new StandardPrettyPrint();
103 }
104
105 /**
106 * visits an ast node and outputs it in dot file format
107 */
108 public void visitASTNode(/*@ non_null */ ASTNode x) {
109 // write the file
110 try {
111 // write the start of the dot file
112 out.write("digraph Test {\n");
113 // call the recursive method on x
114 writeDot(null, x);
115 // write the end of the dot file
116 out.write("}\n");
117 out.close();
118 } catch(IOException exception) {
119 System.out.println("failed to write to file");
120 }
121 }
122
123 public void visitCompilationUnit(/*@ non_null */ CompilationUnit x) {
124 setVisitString("", x.dotId, "CompilationUnit(todo)");
125 }
126
127 public void visitImportDecl(/*@ non_null */ ImportDecl x) {
128 setVisitString("", x.dotId, "ImportDecl(have not seen yet)");
129 }
130
131 public void visitSingleTypeImportDecl(/*@ non_null */ SingleTypeImportDecl x) {
132 setVisitString("", x.dotId, "SingleTypeImportDecl(todo)");
133 }
134
135 public void visitOnDemandImportDecl(/*@ non_null */ OnDemandImportDecl x) {
136 setVisitString("", x.dotId, "OnDemandImportDecl(todo)");
137 }
138
139 public void visitTypeDecl(/*@ non_null */ TypeDecl x) {
140 // get the source text
141 printer.print(source_dump, 0, x);
142 }
143
144 public void visitClassDecl(/*@ non_null */ ClassDecl x) {
145 visitTypeDecl(x);
146 // we need to grab everything before the first { charcter and remove
147 // all the newlines
148 String source = source_dump.toString();
149 char[] source_array = source.substring(0, source.indexOf('{')).toCharArray();
150 for(int count = 0; count < source_array.length; count++) {
151 if(source_array[count] == '\n') source_array[count] = ' ';
152 }
153 source = new String(source_array);
154 setVisitString(source, x.dotId, "ClassDecl");
155 }
156
157 public void visitInterfaceDecl(/*@ non_null */ InterfaceDecl x) {
158 visitTypeDecl(x);
159 // we have to be pretty careful here as we can have interfaces that extend
160 // other interfaces so we need to get everything before the first {
161 // charcter. we also need to replace the newline charcters as well
162 String source = source_dump.toString();
163 char[] source_array = source.substring(0, source.indexOf('{')).toCharArray();
164 for(int count = 0; count < source_array.length; count++) {
165 if(source_array[count] == '\n') source_array[count] = ' ';
166 }
167 source = new String(source_array);
168 setVisitString(source, x.dotId, "InterfaceDecl");
169 }
170
171 public void visitRoutineDecl(/*@ non_null */ RoutineDecl x) {
172 }
173
174 public void visitConstructorDecl(/*@ non_null */ ConstructorDecl x) {
175 // grab the source text
176 printer.print(source_dump, 0, x, x.id(), false);
177 // get everything before the first newline
178 String source = source_dump.toString().substring(0,source_dump.toString().indexOf('\n'));
179 setVisitString(source, x.dotId, "ConstructorDecl");
180 }
181
182 public void visitMethodDecl(/*@ non_null */ MethodDecl x) {
183 // grab the source text
184 printer.print(source_dump, 0, x, x.id(), false);
185 // grab everything before the first newline
186 String source = source_dump.toString().substring(0,source_dump.toString().indexOf('\n'));
187 setVisitString(source, x.dotId, "MethodDecl");
188 }
189
190 public void visitInitBlock(/*@ non_null */ InitBlock x) {
191 setVisitString("", x.dotId, "InitBlock(have not seen yet)");
192 }
193
194 public void visitTypeDeclElemPragma(/*@ non_null */ TypeDeclElemPragma x) {
195 setVisitString("", x.dotId, "TypeDeclElemPragma(have not seen yet)");
196 }
197
198 public void visitGenericVarDecl(/*@ non_null */ GenericVarDecl x) {
199 // get the source text
200 printer.print(source_dump, x);
201 }
202
203 public void visitLocalVarDecl(/*@ non_null */ LocalVarDecl x) {
204 visitGenericVarDecl(x);
205 setVisitString(source_dump.toString(), x.dotId, "LocalVarDecl");
206 }
207
208 public void visitFieldDecl(/*@ non_null */ FieldDecl x) {
209 visitGenericVarDecl(x);
210 setVisitString(source_dump.toString(), x.dotId, "FieldDecl");
211 }
212
213 public void visitFormalParaDecl(/*@ non_null */ FormalParaDecl x) {
214 visitGenericVarDecl(x);
215 setVisitString(source_dump.toString(), x.dotId, "FormalParaDecl");
216 }
217
218 public void visitStmt(/*@ non_null */ Stmt x) {
219 // grab the source text
220 printer.print(source_dump, 0, x);
221 }
222
223 public void visitGenericBlockStmt(/*@ non_null */ GenericBlockStmt x) {
224 visitStmt(x);
225 }
226
227 public void visitBlockStmt(/*@ non_null */ BlockStmt x) {
228 visitGenericBlockStmt(x);
229 setVisitString("", x.dotId, "BlockStmt");
230 }
231
232 public void visitSwitchStmt(/*@ non_null */ SwitchStmt x) {
233 visitStmt(x);
234 // grab everything the first occurence of the ) charcter searching
235 // backwards from the first newline
236 String source = source_dump.toString();
237 source = source.substring(0, source.lastIndexOf(')', source.indexOf('\n')) + 1);
238 setVisitString(source, x.dotId, "SwitchStmt");
239 }
240
241 public void visitAssertStmt(/*@ non_null */ AssertStmt x) {
242 setVisitString("", x.dotId, "AssertStmt(have not seen yet)");
243 }
244
245 public void visitVarDeclStmt(/*@ non_null */ VarDeclStmt x) {
246 visitStmt(x);
247 setVisitString(source_dump.toString(), x.dotId, "VarDeclStmt");
248 }
249
250 public void visitClassDeclStmt(/*@ non_null */ ClassDeclStmt x) {
251 setVisitString("", x.dotId, "ClassDeclStmt(have not seen yet)");
252 }
253
254 public void visitWhileStmt(/*@ non_null */ WhileStmt x) {
255 visitStmt(x);
256 // grab everything from the start of the while statment to the last )
257 // charcter from the first newline
258 String source = source_dump.toString();
259 source = source.substring(0, source.lastIndexOf(')', source.indexOf('\n')) + 1);
260 setVisitString(source, x.dotId, "WhileStmt");
261 }
262
263 public void visitDoStmt(/*@ non_null */ DoStmt x) {
264 visitStmt(x);
265 setVisitString("", x.dotId, "DoStmt");
266 }
267
268 public void visitSynchronizeStmt(/*@ non_null */ SynchronizeStmt x) {
269 setVisitString("", x.dotId, "SynchronizeStmt(have not seen yet)");
270 }
271
272 public void visitEvalStmt(/*@ non_null */ EvalStmt x) {
273 visitStmt(x);
274 setVisitString(source_dump.toString(), x.dotId, "EvalStmt");
275 }
276
277 public void visitReturnStmt(/*@ non_null */ ReturnStmt x) {
278 visitStmt(x);
279 setVisitString(source_dump.toString(), x.dotId, "ReturnStmt");
280 }
281
282 public void visitThrowStmt(/*@ non_null */ ThrowStmt x) {
283 visitStmt(x);
284 setVisitString(source_dump.toString(), x.dotId, "ThrowStmt");
285 }
286
287 public void visitBranchStmt(/*@ non_null */ BranchStmt x) {
288 setVisitString("", x.dotId, "BranchStmt(have not seen yet)");
289 }
290
291 public void visitBreakStmt(/*@ non_null */ BreakStmt x) {
292 visitStmt(x);
293 setVisitString(source_dump.toString(), x.dotId, "BreakStmt");
294 }
295
296 public void visitContinueStmt(/*@ non_null */ ContinueStmt x) {
297 visitStmt(x);
298 setVisitString(source_dump.toString(), x.dotId, "ContinueStmt");
299 }
300
301 public void visitLabelStmt(/*@ non_null */ LabelStmt x) {
302 setVisitString("", x.dotId, "LabelStmt(have not seen yet)");
303 }
304
305 public void visitIfStmt(/*@ non_null */ IfStmt x) {
306 setVisitString("", x.dotId, "IfStmt");
307 }
308
309 public void visitForStmt(/*@ non_null */ ForStmt x) {
310 visitStmt(x);
311 // get everything from the beginning until the last ) charcter is
312 // encountered on the first line
313 String source = source_dump.toString();
314 source = source.substring(0, source.lastIndexOf(')', source.indexOf('\n')) + 1);
315 setVisitString(source, x.dotId, "ForStmt");
316 }
317
318 public void visitSkipStmt(/*@ non_null */ SkipStmt x) {
319 visitStmt(x);
320 setVisitString("", x.dotId, "SkipStmt");
321 }
322
323 public void visitSwitchLabel(/*@ non_null */ SwitchLabel x) {
324 // source string to append to the node label
325 String source = null;
326 visitStmt(x);
327 // we must remove the new line from the label if there is one
328 if(source_dump.toString().indexOf('\n') != -1) source = source_dump.toString().substring(0, source_dump.toString().indexOf('\n'));
329 else source = source_dump.toString();
330 setVisitString(source, x.dotId, "SwitchLabel");
331 }
332
333 public void visitTryFinallyStmt(/*@ non_null */ TryFinallyStmt x) {
334 visitStmt(x.finallyClause);
335 setVisitString("", x.dotId, "TryFinallyStmt");
336 }
337
338 public void visitTryCatchStmt(/*@ non_null */ TryCatchStmt x) {
339 visitStmt(x);
340 // grab the try statment before the first { charcter
341 String source = source_dump.toString();
342 source = source.substring(0, source.indexOf('{'));
343 setVisitString(source, x.dotId, "TryCatchStmt");
344 }
345
346 public void visitStmtPragma(/*@ non_null */ StmtPragma x) {
347 setVisitString("", x.dotId, "StmtPragma(have not seen yet)");
348 }
349
350 public void visitConstructorInvocation(/*@ non_null */ ConstructorInvocation x) {
351 visitStmt(x);
352 setVisitString(source_dump.toString(), x.dotId, "ConstructorInvocation");
353 }
354
355 public void visitCatchClause(/*@ non_null */ CatchClause x) {
356 // we have to do some manual work here as the catch clause is not
357 // really dealt with on its own in the pretty printer.
358 printer.print(source_dump, x.arg);
359
360 setVisitString("catch (" + source_dump.toString() + ")", x.dotId, "CatchClause");
361 }
362
363 public void visitVarInit(/*@ non_null */ VarInit x) {
364 // get the source text
365 printer.print(source_dump, 0, x);
366 }
367
368 public void visitArrayInit(/*@ non_null */ ArrayInit x) {
369 visitVarInit(x);
370 setVisitString(source_dump.toString(), x.dotId, "ArrayInit");
371 }
372
373 public void visitExpr(/*@ non_null */ Expr x) {
374 // grab the source text
375 printer.print(source_dump, 0, x);
376 }
377
378 public void visitThisExpr(/*@ non_null */ ThisExpr x) {
379 visitExpr(x);
380 setVisitString(source_dump.toString(), x.dotId, "ThisExpr");
381 }
382
383 public void visitLiteralExpr(/*@ non_null */ LiteralExpr x) {
384 visitExpr(x);
385 setVisitString(source_dump.toString(), x.dotId, "LiteralExpr");
386 }
387
388 public void visitArrayRefExpr(/*@ non_null */ ArrayRefExpr x) {
389 visitExpr(x);
390 setVisitString(source_dump.toString(), x.dotId, "ArrayRefExpr");
391 }
392
393 public void visitNewInstanceExpr(/*@ non_null */ NewInstanceExpr x) {
394 visitExpr(x);
395 setVisitString(source_dump.toString(), x.dotId, "NewInstanceExpr");
396 }
397
398 public void visitNewArrayExpr(/*@ non_null */ NewArrayExpr x) {
399 visitExpr(x);
400 setVisitString(source_dump.toString(), x.dotId, "NewArrayExpr");
401 }
402
403 public void visitCondExpr(/*@ non_null */ CondExpr x) {
404 setVisitString("", x.dotId, "CondExpr(have not seen yet)");
405 }
406
407 public void visitInstanceOfExpr(/*@ non_null */ InstanceOfExpr x) {
408 visitExpr(x);
409 setVisitString(source_dump.toString(), x.dotId, "InstanceOfExpr");
410 }
411
412 public void visitCastExpr(/*@ non_null */ CastExpr x) {
413 visitExpr(x);
414 setVisitString(source_dump.toString(), x.dotId, "CastExpr");
415 }
416
417 public void visitBinaryExpr(/*@ non_null */ BinaryExpr x) {
418 visitExpr(x);
419 setVisitString(source_dump.toString(), x.dotId, "BinaryExpr");
420 }
421
422 public void visitUnaryExpr(/*@ non_null */ UnaryExpr x) {
423 visitExpr(x);
424 setVisitString(source_dump.toString(), x.dotId, "UnaryExpr");
425 }
426
427 public void visitParenExpr(/*@ non_null */ ParenExpr x) {
428 setVisitString("", x.dotId, "ParenExpr(have not seen yet)");
429 }
430
431 public void visitAmbiguousVariableAccess(/*@ non_null */ AmbiguousVariableAccess x) {
432 setVisitString("", x.dotId, "AmbiguousVariableAccess(have not seen yet)");
433 }
434
435 public void visitVariableAccess(/*@ non_null */ VariableAccess x) {
436 visitExpr(x);
437 setVisitString(source_dump.toString(), x.dotId, "VariableAccess");
438 }
439
440 public void visitFieldAccess(/*@ non_null */ FieldAccess x) {
441 visitExpr(x);
442 setVisitString(source_dump.toString(), x.dotId, "FieldAccess");
443 }
444
445 public void visitAmbiguousMethodInvocation(/*@ non_null */ AmbiguousMethodInvocation x) {
446 setVisitString("", x.dotId, "AmbigousMethodInvocation(have not seen yet)");
447 }
448
449 public void visitMethodInvocation(/*@ non_null */ MethodInvocation x) {
450 visitExpr(x);
451 setVisitString(source_dump.toString(), x.dotId, "MethodInvocation");
452 }
453
454 public void visitClassLiteral(/*@ non_null */ ClassLiteral x) {
455 setVisitString("", x.dotId, "ClassLiteral(have not seen yet)");
456 }
457
458 public void visitObjectDesignator(/*@ non_null */ ObjectDesignator x) {
459 // get the source text
460 printer.print(source_dump, 0, x);
461 }
462
463 public void visitExprObjectDesignator(/*@ non_null */ ExprObjectDesignator x) {
464 visitObjectDesignator(x);
465 setVisitString(source_dump.toString(), x.dotId, "ExprObjectDesignator");
466 }
467
468 public void visitTypeObjectDesignator(/*@ non_null */ TypeObjectDesignator x) {
469 visitObjectDesignator(x);
470 setVisitString("", x.dotId, "TypeObjectDesignator");
471 }
472
473 public void visitSuperObjectDesignator(/*@ non_null */ SuperObjectDesignator x) {
474 visitObjectDesignator(x);
475 setVisitString(source_dump.toString(), x.dotId, "SuperObjectDesignator");
476 }
477
478 public void visitType(/*@ non_null */ Type x) {
479 // get the source text and set the visit string
480 printer.print(source_dump, x);
481 setVisitString(source_dump.toString(), x.dotId, "Type");
482 }
483
484 public void visitErrorType(/*@ non_null */ ErrorType x) {
485 setVisitString("", x.dotId, "ErrorType(have not seen yet)");
486 }
487
488 public void visitPrimitiveType(/*@ non_null */ PrimitiveType x) {
489 // grab the source text as a Type node can appear in the tree
490 printer.print(source_dump, x);
491 setVisitString(source_dump.toString(), x.dotId, "PrimitiveType");
492 }
493
494 public void visitTypeName(/*@ non_null */ TypeName x) {
495 // grab the source text as the generic Type can appear in the tree
496 printer.print(source_dump, x);
497 setVisitString(source_dump.toString(), x.dotId, "TypeName");
498 }
499
500 public void visitArrayType(/*@ non_null */ ArrayType x) {
501 // grab the source text as the generic Type can be in the tree as well
502 printer.print(source_dump, x);
503 setVisitString(source_dump.toString(), x.dotId, "ArrayType");
504 }
505
506 public void visitName(/*@ non_null */ Name x) {
507 // grab the source text
508 printer.print(source_dump, x);
509 }
510
511 public void visitSimpleName(/*@ non_null */ SimpleName x) {
512 visitName(x);
513 setVisitString(source_dump.toString(), x.dotId, "SimpleName");
514 }
515
516 public void visitCompoundName(/*@ non_null */ CompoundName x) {
517 visitName(x);
518 setVisitString(source_dump.toString(), x.dotId, "CompoundName");
519 }
520
521 public void visitModifierPragma(/*@ non_null */ ModifierPragma x) {
522 setVisitString("", x.dotId, "ModifierPragma(have not seen yet)");
523 }
524
525 public void visitLexicalPragma(/*@ non_null */ LexicalPragma x) {
526 setVisitString("", x.dotId, "LexicalPragma(have not seen yet)");
527 }
528
529 public void visitTypeModifierPragma(/*@ non_null */ TypeModifierPragma x) {
530 setVisitString("", x.dotId, "TypeModifierPragma(have not seen yet)");
531 }
532
533 }