1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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
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
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
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
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
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
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 }