View Javadoc

1   /*
2    $Id: ExpressionSupport.java,v 1.1 2004/04/01 06:21:54 cpoirier Exp $
3   
4    Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
5   
6    Redistribution and use of this software and associated documentation
7    ("Software"), with or without modification, are permitted provided
8    that the following conditions are met:
9   
10   1. Redistributions of source code must retain copyright
11      statements and notices.  Redistributions must also contain a
12      copy of this document.
13  
14   2. Redistributions in binary form must reproduce the
15      above copyright notice, this list of conditions and the
16      following disclaimer in the documentation and/or other
17      materials provided with the distribution.
18  
19   3. The name "groovy" must not be used to endorse or promote
20      products derived from this Software without prior written
21      permission of The Codehaus.  For written permission,
22      please contact info@codehaus.org.
23  
24   4. Products derived from this Software may not be called "groovy"
25      nor may "groovy" appear in their names without prior written
26      permission of The Codehaus. "groovy" is a registered
27      trademark of The Codehaus.
28  
29   5. Due credit should be given to The Codehaus -
30      http://groovy.codehaus.org/
31  
32   THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
33   ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
34   NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
35   FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
36   THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
37   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
38   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
39   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
41   STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
42   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
43   OF THE POSSIBILITY OF SUCH DAMAGE.
44  
45   */
46  
47  package org.codehaus.groovy.syntax.parser;
48  
49  import org.codehaus.groovy.syntax.*;
50  
51  
52  
53  /***
54   *  A helper for the expression parsing system that provides in-depth
55   *  analysis of <code>CSTNode</code>s.
56   *
57   *  @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
58   */
59  
60  public class ExpressionSupport
61  {
62  
63    //---------------------------------------------------------------------------
64    // EXPRESSION IDENTIFICATION
65  
66  
67     /***
68      *  Returns true if the node is a complete expression (something that has
69      *  a value).
70      */
71  
72      public static boolean isAnExpression( CSTNode node, boolean unknownReturns )
73      {
74          if( node.isA(Types.UNKNOWN) )
75          {
76              return unknownReturns;
77          }
78  
79          return node.isAnExpression();
80      }
81  
82  
83  
84     /***
85      *  A synonym for <code>isAnExpression( node, false )</code>.
86      */
87  
88      public static boolean isAnExpression( CSTNode node )
89      {
90          return isAnExpression( node, false );
91      }
92  
93  
94  
95  
96    //---------------------------------------------------------------------------
97    // OPERATOR IDENTIFICATION
98  
99  
100    /***
101     *  Returns true if the node is an operator and not an expression (see
102     *  above).
103     */
104 
105     public static boolean isAnOperator( CSTNode node, boolean unknownReturns )
106     {
107         if( node.isA(Types.UNKNOWN) )
108         {
109             return unknownReturns;
110         }
111 
112         return !node.isAnExpression();
113     }
114 
115 
116 
117    /***
118     *  A synonym for <code>isAnOperator(node, false)</code>.
119     */
120 
121     public static boolean isAnOperator( CSTNode node )
122     {
123         return isAnOperator( node, false );
124     }
125 
126 
127 
128 
129   //---------------------------------------------------------------------------
130   // VARIABLE IDENTIFICATION
131 
132 
133    /***
134     *  Returns true if the node might be a variable.
135     */
136 
137     public static boolean isAVariable( CSTNode node )
138     {
139         switch( node.getMeaning() )
140         {
141             case Types.LEFT_SQUARE_BRACKET:
142                 if( node.isAnExpression() )
143                 {
144                    return isAVariable( node.get(1) );
145                 }
146                 break;
147 
148             case Types.DOT:
149             case Types.NAVIGATE:
150             {
151                 if( node.isAnExpression() && node.get(2).getMeaning() == Types.IDENTIFIER )
152                 {
153                     return true;
154                 }
155                 break;
156             }
157 
158             case Types.IDENTIFIER:
159             {
160                 return true;
161             }
162         }
163 
164         return false;
165     }
166 
167 
168 
169 
170   //---------------------------------------------------------------------------
171   // METHOD IDENTIFICATION
172 
173 
174    /***
175     *  Returns true if the node might be a method.
176     */
177 
178     public static boolean isInvokable( CSTNode node )
179     {
180         switch( node.getMeaning() )
181         {
182             case Types.SYNTH_CLOSURE:
183             case Types.SYNTH_METHOD_CALL:
184             case Types.KEYWORD_SUPER:
185             case Types.KEYWORD_THIS:
186                 return true;
187 
188             default:
189                 return isAVariable(node);
190         }
191     }
192 
193 
194 
195 
196   //---------------------------------------------------------------------------
197   // ASSIGNMENT TARGET IDENTIFICATION
198 
199 
200    /***
201     *  Returns true if the node is a modifiable expression (ie. something that
202     *  can be the target of an assignment).  Note that this determination is
203     *  approximate: false negatives won't happen, but false positives are
204     *  distinctly possible, and must be resolved in later phases.
205     */
206 
207     public static boolean isAModifiableExpression( CSTNode node, boolean unknownReturns )
208     {
209         if( isAnExpression(node, unknownReturns) )
210         {
211             if( isAVariable(node) )
212             {
213                 return true;
214             }
215 
216             else if( node.getMeaning() == Types.SYNTH_LIST )
217             {
218                 boolean is = true;
219                 for( int i = 1; i < node.size(); i++ )
220                 {
221                     if( !isAModifiableExpression(node.get(i), unknownReturns) )
222                     {
223                         is = false;
224                         break;
225                     }
226                 }
227                 return is;
228             }
229 
230         }
231 
232         return false;
233     }
234 
235 
236 
237    /***
238     *  A synonym for <code>isAModifiableExpression( node, false )</code>.
239     */
240 
241     public static boolean isAModifiableExpression( CSTNode node )
242     {
243         return isAModifiableExpression( node, false );
244     }
245 
246 
247 
248 
249   //---------------------------------------------------------------------------
250   // TYPE OPERATIONS IDENTIFICATION
251 
252 
253    /***
254     *  Returns true if the node is potentially a cast operator.
255     */
256 
257     public static boolean isPotentialCastOperator( CSTNode node )
258     {
259         if( node.isA(Types.LEFT_PARENTHESIS) && node.isAnExpression() )
260         {
261             return isAPotentialTypeName( node.get(1), false );
262         }
263 
264         return false;
265     }
266 
267 
268 
269    /***
270     *  Returns true if the node is potentially a type name.
271     */
272 
273     public static boolean isAPotentialTypeName( CSTNode node, boolean allowVoid )
274     {
275         if( node.isA(allowVoid ? Types.TYPE_NAME : Types.CREATABLE_TYPE_NAME) )
276         {
277             return true;
278         }
279         else if( node.isA(Types.DOT) && node.isAnExpression() )
280         {
281             return isAPotentialTypeName(node.get(2), allowVoid) && isAPotentialTypeName(node.get(1), allowVoid);
282         }
283         else if( node.isA(Types.LEFT_SQUARE_BRACKET) && node.isAnExpression() && node.size() == 2 )
284         {
285             return isAPotentialTypeName(node.get(1), allowVoid );
286         }
287 
288         return false;
289     }
290 
291 
292 
293 
294 }