KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > hibernate > hql > ast > util > ASTPrinter


1 // $Id: ASTPrinter.java,v 1.1 2005/07/12 20:27:17 steveebersole Exp $
2
package org.hibernate.hql.ast.util;
3
4 import java.io.ByteArrayOutputStream JavaDoc;
5 import java.io.PrintStream JavaDoc;
6 import java.io.PrintWriter JavaDoc;
7 import java.lang.reflect.Field JavaDoc;
8 import java.lang.reflect.Modifier JavaDoc;
9 import java.util.ArrayList JavaDoc;
10 import java.util.HashMap JavaDoc;
11 import java.util.Map JavaDoc;
12
13 import org.hibernate.hql.ast.tree.DisplayableNode;
14 import org.hibernate.util.StringHelper;
15
16 import antlr.collections.AST;
17
18 /**
19  * An 'ASCII art' AST printer for debugging ANTLR grammars.
20  *
21  * @author Joshua Davis (pgmjsd@sourceforge.net)
22  */

23 public class ASTPrinter {
24     private Map JavaDoc tokenTypeNamesByTokenType;
25     private Class JavaDoc tokenTypeConstants;
26     private boolean showClassNames = true;
27
28     /**
29      * Constructs an org.hibernate.hql.antlr.ASTPrinter, given the class that contains the token type
30      * constants (typically the '{grammar}TokenTypes' interface generated by
31      * ANTLR).
32      *
33      * @param tokenTypeConstants The class with token type constants in it.
34      */

35     public ASTPrinter(Class JavaDoc tokenTypeConstants) {
36         this.tokenTypeConstants = tokenTypeConstants;
37     }
38
39     /**
40      * Returns true if the node class names will be displayed.
41      *
42      * @return true if the node class names will be displayed.
43      */

44     public boolean isShowClassNames() {
45         return showClassNames;
46     }
47
48     /**
49      * Enables or disables AST node class name display.
50      *
51      * @param showClassNames true to enable class name display, false to disable
52      */

53     public void setShowClassNames(boolean showClassNames) {
54         this.showClassNames = showClassNames;
55     }
56
57     /**
58      * Prints the AST in 'ASCII art' tree form to the specified print stream.
59      *
60      * @param ast The AST to print.
61      * @param out The print stream.
62      */

63     private void showAst(AST ast, PrintStream JavaDoc out) {
64         showAst( ast, new PrintWriter JavaDoc( out ) );
65     }
66
67     /**
68      * Prints the AST in 'ASCII art' tree form to the specified print writer.
69      *
70      * @param ast The AST to print.
71      * @param pw The print writer.
72      */

73     public void showAst(AST ast, PrintWriter JavaDoc pw) {
74         ArrayList JavaDoc parents = new ArrayList JavaDoc();
75         showAst( parents, pw, ast );
76         pw.flush();
77     }
78
79     /**
80      * Prints the AST in 'ASCII art' tree form into a string.
81      *
82      * @param ast The AST to display.
83      * @param header The header for the display.
84      * @return The AST in 'ASCII art' form, as a string.
85      */

86     public String JavaDoc showAsString(AST ast, String JavaDoc header) {
87         ByteArrayOutputStream JavaDoc baos = new ByteArrayOutputStream JavaDoc();
88         PrintStream JavaDoc ps = new PrintStream JavaDoc( baos );
89         ps.println( header );
90         showAst( ast, ps );
91         ps.flush();
92         return new String JavaDoc( baos.toByteArray() );
93     }
94
95     /**
96      * Get a single token type name in the specified set of token type constants (interface).
97      *
98      * @param tokenTypeConstants Token type constants interface (e.g. HqlSqlTokenTypes.class).
99      * @param type The token type ( typically from ast.getType() ).
100      * @return The token type name, *or* the integer value if the name could not be found for some reason.
101      */

102     public static String JavaDoc getConstantName(Class JavaDoc tokenTypeConstants, int type) {
103         String JavaDoc tokenTypeName = null;
104         if ( tokenTypeConstants != null ) {
105             Field JavaDoc[] fields = tokenTypeConstants.getFields();
106             for ( int i = 0; i < fields.length; i++ ) {
107                 Field JavaDoc field = fields[i];
108                 tokenTypeName = getTokenTypeName( field, type, true );
109                 if ( tokenTypeName != null ) {
110                     break; // Stop if found.
111
}
112             } // for
113
} // if type constants were provided
114

115         // Use the integer value if no token type name was found
116
if ( tokenTypeName == null ) {
117             tokenTypeName = Integer.toString( type );
118         }
119
120         return tokenTypeName;
121     }
122
123     private static String JavaDoc getTokenTypeName(Field JavaDoc field, int type, boolean checkType) {
124         if ( Modifier.isStatic( field.getModifiers() ) ) {
125             try {
126                 Object JavaDoc value = field.get( null );
127                 if ( !checkType ) {
128                     return field.getName();
129                 }
130                 else if ( value instanceof Integer JavaDoc ) {
131                     Integer JavaDoc integer = ( Integer JavaDoc ) value;
132                     if ( integer.intValue() == type ) {
133                         return field.getName();
134                     }
135                 } // if value is an integer
136
} // try
137
catch ( IllegalArgumentException JavaDoc ignore ) {
138             }
139             catch ( IllegalAccessException JavaDoc ignore ) {
140             }
141         } // if the field is static
142
return null;
143     }
144
145     /**
146      * Returns the token type name for the given token type.
147      *
148      * @param type The token type.
149      * @return String - The token type name from the token type constant class,
150      * or just the integer as a string if none exists.
151      */

152     private String JavaDoc getTokenTypeName(int type) {
153         // If the class with the constants in it was not supplied, just
154
// use the integer token type as the token type name.
155
if ( tokenTypeConstants == null ) {
156             return Integer.toString( type );
157         }
158
159         // Otherwise, create a type id -> name map from the class if it
160
// hasn't already been created.
161
if ( tokenTypeNamesByTokenType == null ) {
162             Field JavaDoc[] fields = tokenTypeConstants.getFields();
163             tokenTypeNamesByTokenType = new HashMap JavaDoc();
164             String JavaDoc tokenTypeName = null;
165             for ( int i = 0; i < fields.length; i++ ) {
166                 Field JavaDoc field = fields[i];
167                 tokenTypeName = getTokenTypeName( field, type, false );
168                 if ( tokenTypeName != null ) {
169                     try {
170                         tokenTypeNamesByTokenType.put( field.get( null ), field.getName() );
171                     }
172                     catch ( IllegalAccessException JavaDoc ignore ) {
173                     }
174                 }
175             } // for
176
} // if the map hasn't been created.
177

178         return ( String JavaDoc ) tokenTypeNamesByTokenType.get( new Integer JavaDoc( type ) );
179     }
180
181     private void showAst(ArrayList JavaDoc parents, PrintWriter JavaDoc pw, AST ast) {
182         if ( ast == null ) {
183             pw.println( "AST is null!" );
184             return;
185         }
186
187         for ( int i = 0; i < parents.size(); i++ ) {
188             AST parent = ( AST ) parents.get( i );
189             if ( parent.getNextSibling() == null ) {
190
191                 pw.print( " " );
192             }
193             else {
194                 pw.print( " | " );
195             }
196         }
197
198         if ( ast.getNextSibling() == null ) {
199             pw.print( " \\-" );
200         }
201         else {
202             pw.print( " +-" );
203         }
204
205         showNode( pw, ast );
206
207         ArrayList JavaDoc newParents = new ArrayList JavaDoc( parents );
208         newParents.add( ast );
209         for ( AST child = ast.getFirstChild(); child != null; child = child.getNextSibling() ) {
210             showAst( newParents, pw, child );
211         }
212         newParents.clear();
213     }
214
215     private void showNode(PrintWriter JavaDoc pw, AST ast) {
216         String JavaDoc s = nodeToString( ast, isShowClassNames() );
217         pw.println( s );
218     }
219
220     public String JavaDoc nodeToString(AST ast, boolean showClassName) {
221         if ( ast == null ) {
222             return "{null}";
223         }
224         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
225         buf.append( "[" ).append( getTokenTypeName( ast.getType() ) ).append( "] " );
226         if ( showClassName ) {
227             buf.append( StringHelper.unqualify( ast.getClass().getName() ) ).append( ": " );
228         }
229
230         buf.append( "'" );
231         String JavaDoc text = ast.getText();
232         appendEscapedMultibyteChars(text, buf);
233         buf.append( "'" );
234         if ( ast instanceof DisplayableNode ) {
235             DisplayableNode displayableNode = ( DisplayableNode ) ast;
236             // Add a space before the display text.
237
buf.append( " " ).append( displayableNode.getDisplayText() );
238         }
239         String JavaDoc s = buf.toString();
240         return s;
241     }
242
243     public static void appendEscapedMultibyteChars(String JavaDoc text, StringBuffer JavaDoc buf) {
244         char[] chars = text.toCharArray();
245         for (int i = 0; i < chars.length; i++) {
246             char aChar = chars[i];
247             if (aChar > 256) {
248                 buf.append("\\u");
249                 buf.append(Integer.toHexString(aChar));
250             }
251             else
252                 buf.append(aChar);
253         }
254     }
255
256     public static String JavaDoc escapeMultibyteChars(String JavaDoc text)
257     {
258         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
259         appendEscapedMultibyteChars(text,buf);
260         return buf.toString();
261     }
262 }
263
Popular Tags