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 package org.codehaus.groovy.ast.expr;
47
48 import java.io.OutputStream;
49 import java.io.Writer;
50 import java.math.BigDecimal;
51 import java.math.BigInteger;
52 import java.util.Collection;
53 import java.util.Date;
54 import java.util.List;
55 import java.util.Map;
56 import java.util.regex.Matcher;
57
58 import org.codehaus.groovy.ast.GroovyCodeVisitor;
59 import org.codehaus.groovy.ast.Type;
60 import org.codehaus.groovy.classgen.AsmClassGenerator2;
61 import org.codehaus.groovy.syntax.Token;
62 import org.codehaus.groovy.syntax.Types;
63 import groovy.lang.GString;
64
65 /***
66 * Represents two expressions and an operation
67 *
68 * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
69 * @version $Revision: 1.6 $
70 */
71 public class BinaryExpression extends Expression {
72
73 private Expression leftExpression;
74 private Expression rightExpression;
75 private Token operation;
76
77 public BinaryExpression(Expression leftExpression,
78 Token operation,
79 Expression rightExpression) {
80 this.leftExpression = leftExpression;
81 this.operation = operation;
82 this.rightExpression = rightExpression;
83
84 }
85
86 public Class getTypeClass() {
87 typeClass = resolveThisType(operation);
88 return typeClass;
89 }
90
91 public boolean isDynamic() {
92 return false;
93 }
94
95 private Class resolveThisType(Token operation) {
96 switch (operation.getType()) {
97 case Types.EQUAL :
98 if (!leftExpression.isDynamic())
99 return leftExpression.getTypeClass();
100 else
101 return rightExpression.getTypeClass();
102 case Types.COMPARE_IDENTICAL :
103 case Types.COMPARE_EQUAL :
104 case Types.COMPARE_NOT_EQUAL :
105 case Types.COMPARE_GREATER_THAN :
106 case Types.COMPARE_GREATER_THAN_EQUAL :
107 case Types.COMPARE_LESS_THAN :
108 case Types.COMPARE_LESS_THAN_EQUAL :
109 case Types.KEYWORD_INSTANCEOF :
110 case Types.MATCH_REGEX :
111 return boolean.class;
112 case Types.LOGICAL_AND :
113 case Types.LOGICAL_OR :
114 return Boolean.class;
115 case Types.COMPARE_TO :
116 return Integer.class;
117 case Types.PLUS :
118 case Types.PLUS_EQUAL :{
119 if (leftExpression.getTypeClass() == String.class && rightExpression.getTypeClass() == String.class) {
120 return String.class;
121 }
122 else if (leftExpression.getTypeClass() == GString.class &&
123 (rightExpression.getTypeClass() == GString.class || rightExpression.getTypeClass() == String.class)) {
124 return GString.class;
125 }
126 else if (isNumber(leftExpression.getType()) && isNumber(rightExpression.getType())) {
127 return chooseWiderNumberType(leftExpression.getType(), rightExpression.getType());
128 }
129 else if (leftExpression.getTypeClass() == Date.class && Number.class.isAssignableFrom(rightExpression.getTypeClass()) ) {
130 return Date.class;
131 }
132 else if (leftExpression.getTypeClass() != null && Collection.class.isAssignableFrom(leftExpression.getTypeClass() )) {
133 return List.class;
134 }
135 else {
136 return null;
137 }
138 }
139 case Types.MINUS :
140 case Types.MINUS_EQUAL :{
141 if (leftExpression.getTypeClass() == String.class) {
142 return String.class;
143 } else if (leftExpression instanceof GStringExpression && isNumber(rightExpression.getType())) {
144 return String.class;
145 } else if (isNumber(leftExpression.getType()) && isNumber(rightExpression.getType())) {
146 return chooseWiderNumberType(leftExpression.getType(), rightExpression.getType());
147 }
148 else if (leftExpression.getTypeClass() != null && List.class.isAssignableFrom(leftExpression.getTypeClass() )) {
149 return List.class;
150 }
151 else if (leftExpression.getTypeClass() == Date.class && Number.class.isAssignableFrom(rightExpression.getTypeClass()) ) {
152 return Date.class;
153 }
154 else {
155 return null;
156 }
157 }
158 case Types.MULTIPLY :
159 case Types.MULTIPLY_EQUAL : {
160 if (leftExpression.getTypeClass() == String.class && isNumber(rightExpression.getType())) {
161 return String.class;
162 } else if (leftExpression instanceof GStringExpression && isNumber(rightExpression.getType())) {
163 return String.class;
164 } else if (isNumber(leftExpression.getType()) && isNumber(rightExpression.getType())) {
165 return chooseWiderNumberType(leftExpression.getType(), rightExpression.getType());
166 }
167 else if (leftExpression.getTypeClass() != null && Collection.class.isAssignableFrom(leftExpression.getTypeClass() )) {
168 return List.class;
169 }
170 else {
171 return null;
172 }
173 }
174
175 case Types.DIVIDE :
176 case Types.DIVIDE_EQUAL :
177 case Types.MOD :
178 case Types.MOD_EQUAL :
179 if (isNumber(leftExpression.getType()) && isNumber(rightExpression.getType())) {
180 return chooseWiderNumberType(leftExpression.getType(), rightExpression.getType());
181 }
182 return null;
183 case Types.LEFT_SHIFT :
184 if (isNumber(leftExpression.getType()) && isNumber(rightExpression.getType())) {
185 return leftExpression.getTypeClass();
186 }
187 else if (leftExpression.getTypeClass() != null && Collection.class.isAssignableFrom(leftExpression.getTypeClass() )) {
188 return Collection.class;
189 }
190 else if (leftExpression.getTypeClass() != null && OutputStream.class.isAssignableFrom(leftExpression.getTypeClass())) {
191 return Writer.class;
192 }
193 else if (leftExpression.getTypeClass() != null && StringBuffer.class.isAssignableFrom(leftExpression.getTypeClass())) {
194 return Writer.class;
195 }
196 return null;
197 case Types.RIGHT_SHIFT :
198 case Types.RIGHT_SHIFT_UNSIGNED :
199 if (isNumber(leftExpression.getType()) && isNumber(rightExpression.getType())) {
200 return leftExpression.getTypeClass();
201 }
202 return null;
203 case Types.FIND_REGEX :
204 return Matcher.class;
205 case Types.LEFT_SQUARE_BRACKET :
206 Class cls = leftExpression.getTypeClass();
207 if (cls != null) {
208 if (cls.isArray()) {
209 Class elemType = cls.getComponentType();
210
211 return elemType;
212 }
213 else if (leftExpression instanceof ListExpression) {
214 Class elemType = ((ListExpression)leftExpression).getComponentTypeClass();
215
216 return elemType;
217 }
218 else if (leftExpression instanceof MapExpression) {
219 return Object.class;
220 }
221 else if (List.class.isAssignableFrom(cls)) {
222 return (Object.class);
223 }
224 else if (Map.class.isAssignableFrom(cls)) {
225 return (Object.class);
226 }
227 }
228 break;
229 }
230 return null;
231 }
232
233 private static boolean isNumber(String type) {
234 if (type!= null) {
235 if ( type.equals("int") ||
236 type.equals("short") ||
237 type.equals("byte") ||
238 type.equals("char") ||
239 type.equals("float") ||
240 type.equals("long") ||
241 type.equals("double") ||
242 type.equals("java.lang.Short") ||
243 type.equals("java.lang.Byte") ||
244 type.equals("java.lang.Character") ||
245 type.equals("java.lang.Integer") ||
246 type.equals("java.lang.Float") ||
247 type.equals("java.lang.Long") ||
248 type.equals("java.lang.Double") ||
249 type.equals("java.math.BigInteger") ||
250 type.equals("java.math.BigDecimal"))
251 {
252 return true;
253 }
254 }
255 return false;
256 }
257
258 private static Class getObjectClassForNumber(String type) {
259 if (type.equals("boolean") || type.equals("java.lang.Boolean")) {
260 return Boolean.class;
261 }
262 else if (type.equals("short") || type.equals("java.lang.Short")) {
263 return Short.class;
264 }
265 else if (type.equals("int") || type.equals("java.lang.Integer")) {
266 return Integer.class;
267 }
268 else if (type.equals("char") || type.equals("java.lang.Character")) {
269 return Integer.class;
270 }
271 else if (type.equals("long") || type.equals("java.lang.Long")) {
272 return Long.class;
273 }
274 else if (type.equals("float") || type.equals("java.lang.Float")) {
275 return Float.class;
276 }
277 else if (type.equals("double") || type.equals("java.lang.Double")) {
278 return Double.class;
279 }
280 else if (type.equals("java.math.BigInteger")) {
281 return BigInteger.class;
282 }
283 else if (type.equals("java.math.BigDecimal")) {
284 return BigDecimal.class;
285 }
286 else {
287 return null;
288 }
289 }
290
291 private static boolean isFloatingPoint(Class cls) {
292 return cls == Double.class || cls == Float.class;
293 }
294
295 private static boolean isInteger(Class cls) {
296 return cls == Integer.class || cls == Byte.class || cls == Short.class || cls == Character.class;
297 }
298
299 private static boolean isLong(Class cls) {
300 return cls == Long.class;
301 }
302
303 private static boolean isBigDecimal(Class cls) {
304 return cls == BigDecimal.class;
305 }
306
307 private static boolean isBigInteger(Class cls) {
308 return cls == BigInteger.class;
309 }
310
311 private static Class chooseWiderNumberType(String lefts, String rights) {
312 Class left = getObjectClassForNumber(lefts);
313 Class right = getObjectClassForNumber(rights);
314 if (isFloatingPoint(left) || isFloatingPoint(right)) {
315 return Double.class;
316 }
317 else if (isBigDecimal(left) || isBigDecimal(right)) {
318 return BigDecimal.class;
319 }
320 else if (isBigInteger(left) || isBigInteger(right)) {
321 return BigInteger.class;
322 }
323 else if (isLong(left) || isLong(right)){
324 return Long.class;
325 }
326 return Integer.class;
327
328
329 }
330 public String toString() {
331 return super.toString() +"[" + leftExpression + operation + rightExpression + "]";
332 }
333
334 public void visit(GroovyCodeVisitor visitor) {
335 visitor.visitBinaryExpression(this);
336 }
337
338 public Expression transformExpression(ExpressionTransformer transformer) {
339 return new BinaryExpression(transformer.transform(leftExpression), operation, transformer.transform(rightExpression));
340 }
341
342 public Expression getLeftExpression() {
343 return leftExpression;
344 }
345
346 public void setLeftExpression(Expression leftExpression) {
347 this.leftExpression = leftExpression;
348 }
349
350 public void setRightExpression(Expression rightExpression) {
351 this.rightExpression = rightExpression;
352 }
353
354 public Token getOperation() {
355 return operation;
356 }
357
358 public Expression getRightExpression() {
359 return rightExpression;
360 }
361
362 public String getText() {
363 if (operation.getType() == Types.LEFT_SQUARE_BRACKET) {
364 return leftExpression.getText() + "[" + rightExpression.getText() + "]";
365 }
366 return "(" + leftExpression.getText() + " " + operation.getText() + " " + rightExpression.getText() + ")";
367 }
368
369
370 /***
371 * Creates an assignment expression in which the specified expression
372 * is written into the specified variable name.
373 */
374
375 public static BinaryExpression newAssignmentExpression( String variable, Expression rhs ) {
376 VariableExpression lhs = new VariableExpression( variable );
377 Token operator = Token.newPlaceholder( Types.ASSIGN );
378
379 return new BinaryExpression( lhs, operator, rhs );
380 }
381
382
383 /***
384 * Creates variable initialization expression in which the specified expression
385 * is written into the specified variable name.
386 */
387
388 public static BinaryExpression newInitializationExpression( String variable, Type type, Expression rhs ) {
389 VariableExpression lhs = new VariableExpression( variable );
390
391 if( type != null ) {
392 lhs.setType( type.getName() );
393 }
394
395 Token operator = Token.newPlaceholder( Types.ASSIGN );
396
397 return new BinaryExpression( lhs, operator, rhs );
398 }
399
400 protected void resolveType(AsmClassGenerator2 resolver) {
401 leftExpression.resolve(resolver);
402 rightExpression.resolve(resolver);
403 Class cls = resolveThisType(operation);
404 if (cls != null) {
405 setTypeClass(cls);
406 }
407 else {
408 setResolveFailed(true);
409 setFailure("unknown. the right expression may have not been resolved");
410 }
411 }
412 }