View Javadoc

1   package org.apache.commons.ognl;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.math.BigDecimal;
23  import java.math.BigInteger;
24  
25  /**
26   * A NodeVisitor implementation which will build a String representation of the AST tree.
27   * <p/>
28   * This class is meant to be used by SimpleNode.toString(), but you may use it to
29   *
30   * @since 4.0
31   * @author Daniel Pitts
32   */
33  public class ToStringVisitor
34      implements NodeVisitor<StringBuilder, StringBuilder>
35  {
36      static final ToStringVisitor INSTANCE = new ToStringVisitor();
37  
38      public StringBuilder visit( ASTSequence node, StringBuilder data )
39      {
40          return commaSeparatedChildren( node, data );
41      }
42  
43      private StringBuilder commaSeparatedChildren( SimpleNode node, StringBuilder data )
44      {
45          if ( ( node.children != null ) )
46          {
47              for ( int i = 0; i < node.children.length; ++i )
48              {
49                  if ( i > 0 )
50                  {
51                      data.append( ", " );
52                  }
53                  recurse( node.children[i], data );
54              }
55          }
56          return data;
57      }
58  
59      public StringBuilder visit( ASTAssign node, StringBuilder data )
60      {
61          return concatInfix( node, " = ", data );
62      }
63  
64      public StringBuilder visit( ASTTest node, StringBuilder data )
65      {
66          return visitExpressionNode( node, data );
67      }
68  
69      private StringBuilder visitExpressionNode( ExpressionNode node, StringBuilder data )
70      {
71          if ( node.parent != null )
72          {
73              data.append( "(" );
74          }
75  
76          if ( ( node.children != null ) && ( node.children.length > 0 ) )
77          {
78              for ( int i = 0; i < node.children.length; ++i )
79              {
80                  if ( i > 0 )
81                  {
82                      data.append( " " ).append( node.getExpressionOperator( i ) ).append( " " );
83                  }
84                  recurse( node.children[i], data );
85              }
86          }
87  
88          if ( node.parent != null )
89          {
90              data.append( ')' );
91          }
92          return data;
93      }
94  
95      public StringBuilder visit( ASTOr node, StringBuilder data )
96      {
97          return visitExpressionNode( node, data );
98      }
99  
100     public StringBuilder visit( ASTAnd node, StringBuilder data )
101     {
102         return visitExpressionNode( node, data );
103     }
104 
105     public StringBuilder visit( ASTBitOr node, StringBuilder data )
106     {
107         return visitExpressionNode( node, data );
108     }
109 
110     public StringBuilder visit( ASTXor node, StringBuilder data )
111     {
112         return visitExpressionNode( node, data );
113     }
114 
115     public StringBuilder visit( ASTBitAnd node, StringBuilder data )
116     {
117         return visitExpressionNode( node, data );
118     }
119 
120     public StringBuilder visit( ASTEq node, StringBuilder data )
121     {
122         return visitExpressionNode( node, data );
123     }
124 
125     public StringBuilder visit( ASTNotEq node, StringBuilder data )
126     {
127         return visitExpressionNode( node, data );
128     }
129 
130     public StringBuilder visit( ASTLess node, StringBuilder data )
131     {
132         return visitExpressionNode( node, data );
133     }
134 
135     public StringBuilder visit( ASTGreater node, StringBuilder data )
136     {
137         return visitExpressionNode( node, data );
138     }
139 
140     public StringBuilder visit( ASTLessEq node, StringBuilder data )
141     {
142         return visitExpressionNode( node, data );
143     }
144 
145     public StringBuilder visit( ASTGreaterEq node, StringBuilder data )
146     {
147         return visitExpressionNode( node, data );
148     }
149 
150     public StringBuilder visit( ASTIn node, StringBuilder data )
151     {
152         final String infix = " in ";
153         return concatInfix( node, infix, data );
154     }
155 
156     private StringBuilder concatInfix( SimpleNode node, String infix, StringBuilder data )
157     {
158         return concatInfix( node.children[0], infix, node.children[1], data );
159     }
160 
161     private StringBuilder concatInfix( Node left, String infix, Node right, StringBuilder data )
162     {
163         recurse( left, data ).append( infix );
164         return recurse( right, data );
165     }
166 
167     public StringBuilder visit( ASTNotIn node, StringBuilder data )
168     {
169         return concatInfix( node, " not in ", data );
170     }
171 
172     public StringBuilder visit( ASTShiftLeft node, StringBuilder data )
173     {
174         return visitExpressionNode( node, data );
175     }
176 
177     public StringBuilder visit( ASTShiftRight node, StringBuilder data )
178     {
179         return visitExpressionNode( node, data );
180     }
181 
182     public StringBuilder visit( ASTUnsignedShiftRight node, StringBuilder data )
183     {
184         return visitExpressionNode( node, data );
185     }
186 
187     public StringBuilder visit( ASTAdd node, StringBuilder data )
188     {
189         return visitExpressionNode( node, data );
190     }
191 
192     public StringBuilder visit( ASTSubtract node, StringBuilder data )
193     {
194         return visitExpressionNode( node, data );
195     }
196 
197     public StringBuilder visit( ASTMultiply node, StringBuilder data )
198     {
199         return visitExpressionNode( node, data );
200     }
201 
202     public StringBuilder visit( ASTDivide node, StringBuilder data )
203     {
204         return visitExpressionNode( node, data );
205     }
206 
207     public StringBuilder visit( ASTRemainder node, StringBuilder data )
208     {
209         return visitExpressionNode( node, data );
210     }
211 
212     public StringBuilder visit( ASTNegate node, StringBuilder data )
213     {
214         return appendPrefixed( "-", node, data );
215     }
216 
217     public StringBuilder visit( ASTBitNegate node, StringBuilder data )
218     {
219         return appendPrefixed( "~", node, data );
220     }
221 
222     private StringBuilder appendPrefixed( String prefix, SimpleNode node, StringBuilder data )
223     {
224         data.append( prefix );
225         return recurse( node.children[0], data );
226     }
227 
228     public StringBuilder visit( ASTNot node, StringBuilder data )
229     {
230         return visitExpressionNode( node, data );
231     }
232 
233     public StringBuilder visit( ASTInstanceof node, StringBuilder data )
234     {
235         return recurse( node.children[0], data ).append( " instanceof " ).append( node.getTargetType() );
236     }
237 
238     public StringBuilder visit( ASTChain node, StringBuilder data )
239     {
240 
241         if ( ( node.children != null ) && ( node.children.length > 0 ) )
242         {
243             for ( int i = 0; i < node.children.length; i++ )
244             {
245                 if ( i > 0 )
246                 {
247                     if ( !( node.children[i] instanceof ASTProperty )
248                         || !( (ASTProperty) node.children[i] ).isIndexedAccess() )
249                     {
250                         data.append( "." );
251                     }
252                 }
253                 recurse( node.children[i], data );
254             }
255         }
256         return data;
257     }
258 
259     public StringBuilder visit( ASTEval node, StringBuilder data )
260     {
261         data.append( "(" );
262         concatInfix( node, ")(", data );
263         return data.append( ")" );
264     }
265 
266     public StringBuilder visit( ASTConst node, StringBuilder data )
267     {
268         final Object value = node.getValue();
269         if ( value == null )
270         {
271             data.append( "null" );
272         }
273         else
274         {
275             if ( value instanceof String )
276             {
277                 data.append( '\"' ).append( OgnlOps.getEscapeString( value.toString() ) ).append( '\"' );
278             }
279             else
280             {
281                 if ( value instanceof Character )
282                 {
283                     data.append( '\'' ).append( OgnlOps.getEscapedChar( (Character) value ) ).append( '\'' );
284                 }
285                 else
286                 {
287                     if ( value instanceof Node )
288                     {
289                         data.append( ":[ " );
290                         recurse( (Node) value, data );
291                         data.append( " ]" );
292                     }
293                     else
294                     {
295                         data.append( value );
296                         if ( value instanceof Long )
297                         {
298                             data.append( 'L' );
299                         }
300                         else if ( value instanceof BigDecimal )
301                         {
302                             data.append( 'B' );
303                         }
304                         else if ( value instanceof BigInteger )
305                         {
306                             data.append( 'H' );
307                         }
308                     }
309                 }
310             }
311         }
312         return data;
313     }
314 
315     public StringBuilder visit( ASTThisVarRef node, StringBuilder data )
316     {
317         return data.append( "#this" );
318     }
319 
320     public StringBuilder visit( ASTRootVarRef node, StringBuilder data )
321     {
322         return data.append( "#root" );
323     }
324 
325     public StringBuilder visit( ASTVarRef node, StringBuilder data )
326     {
327         return data.append( "#" ).append( node.getName() );
328     }
329 
330     public StringBuilder visit( ASTList node, StringBuilder data )
331     {
332         return wrappedCommaSeparatedChildren( "{ ", node, " }", data );
333     }
334 
335     public StringBuilder visit( ASTMap node, StringBuilder data )
336     {
337         data.append( "#" );
338 
339         if ( node.getClassName() != null )
340         {
341             data.append( "@" ).append( node.getClassName() ).append( "@" );
342         }
343 
344         data.append( "{ " );
345         for ( int i = 0; i < node.jjtGetNumChildren(); ++i )
346         {
347             ASTKeyValue kv = (ASTKeyValue) node.children[i];
348 
349             if ( i > 0 )
350             {
351                 data.append( ", " );
352             }
353             concatInfix( kv.getKey(), " : ", kv.getValue(), data );
354         }
355         return data.append( " }" );
356     }
357 
358     public StringBuilder visit( ASTKeyValue node, StringBuilder data )
359     {
360         return concatInfix( node.getKey(), " -> ", node.getValue(), data );
361     }
362 
363     public StringBuilder visit( ASTStaticField node, StringBuilder data )
364     {
365         return data.append( "@" ).append( node.getClassName() ).append( "@" ).append( node.getFieldName() );
366     }
367 
368     public StringBuilder visit( ASTCtor node, StringBuilder data )
369     {
370         data.append( "new " ).append( node.getClassName() );
371 
372         if ( node.isArray() )
373         {
374             if ( node.children[0] instanceof ASTConst )
375             {
376                 indexedChild( node, data );
377             }
378             else
379             {
380                 appendPrefixed( "[] ", node, data );
381             }
382         }
383         else
384         {
385             wrappedCommaSeparatedChildren( "(", node, ")", data );
386         }
387         return data;
388     }
389 
390     private StringBuilder wrappedCommaSeparatedChildren( String prefix, SimpleNode node, String suffix,
391                                                          StringBuilder data )
392     {
393         data.append( prefix );
394         return commaSeparatedChildren( node, data ).append( suffix );
395     }
396 
397     public StringBuilder visit( ASTProperty node, StringBuilder data )
398     {
399         if ( node.isIndexedAccess() )
400         {
401             indexedChild( node, data );
402         }
403         else
404         {
405             data.append( ( (ASTConst) node.children[0] ).getValue() );
406         }
407         return data;
408     }
409 
410     private StringBuilder indexedChild( SimpleNode node, StringBuilder data )
411     {
412         return surroundedNode( "[", node.children[0], "]", data );
413     }
414 
415     public StringBuilder visit( ASTStaticMethod node, StringBuilder data )
416     {
417         data.append( "@" ).append( node.getClassName() ).append( "@" ).append( node.getMethodName() );
418         return wrappedCommaSeparatedChildren( "(", node, ")", data );
419     }
420 
421     public StringBuilder visit( ASTMethod node, StringBuilder data )
422     {
423         data.append( node.getMethodName() );
424         return wrappedCommaSeparatedChildren( "(", node, ")", data );
425     }
426 
427     public StringBuilder visit( ASTProject node, StringBuilder data )
428     {
429         return surroundedNode( "{ ", node.children[0], " }", data );
430     }
431 
432     private StringBuilder surroundedNode( String open, Node inner, String close, StringBuilder data )
433     {
434         data.append( open );
435         return recurse( inner, data ).append( close );
436     }
437 
438     public StringBuilder visit( ASTSelect node, StringBuilder data )
439     {
440         return surroundedNode( "{? ", node.children[0], " }", data );
441     }
442 
443     public StringBuilder visit( ASTSelectFirst node, StringBuilder data )
444     {
445         return surroundedNode( "{^ ", node.children[0], " }", data );
446     }
447 
448     public StringBuilder visit( ASTSelectLast node, StringBuilder data )
449     {
450         return surroundedNode( "{$ ", node.children[0], " }", data );
451     }
452 
453     private StringBuilder recurse( Node child, StringBuilder data )
454     {
455         try
456         {
457             return child == null ? data.append( "null" ) : child.accept( this, data );
458         }
459         catch ( OgnlException e )
460         {
461             // This should never happen, but delegate it on just in case.
462             throw new RuntimeException( e );
463         }
464     }
465 
466 }