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    }