KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > polyglot > ext > jl > ast > Binary_c


1 package polyglot.ext.jl.ast;
2
3 import polyglot.ast.*;
4 import polyglot.util.*;
5 import polyglot.visit.*;
6 import polyglot.types.*;
7
8 import java.util.*;
9
10 /**
11  * A <code>Binary</code> represents a Java binary expression, an
12  * immutable pair of expressions combined with an operator.
13  */

14 public class Binary_c extends Expr_c implements Binary
15 {
16     protected Expr left;
17     protected Operator op;
18     protected Expr right;
19     protected Precedence precedence;
20
21     public Binary_c(Position pos, Expr left, Operator op, Expr right) {
22     super(pos);
23     this.left = left;
24     this.op = op;
25     this.right = right;
26     this.precedence = op.precedence();
27     }
28
29     /** Get the left operand of the expression. */
30     public Expr left() {
31     return this.left;
32     }
33
34     /** Set the left operand of the expression. */
35     public Binary left(Expr left) {
36     Binary_c n = (Binary_c) copy();
37     n.left = left;
38     return n;
39     }
40
41     /** Get the operator of the expression. */
42     public Operator operator() {
43     return this.op;
44     }
45
46     /** Set the operator of the expression. */
47     public Binary operator(Operator op) {
48     Binary_c n = (Binary_c) copy();
49     n.op = op;
50     return n;
51     }
52
53     /** Get the right operand of the expression. */
54     public Expr right() {
55     return this.right;
56     }
57
58     /** Set the right operand of the expression. */
59     public Binary right(Expr right) {
60     Binary_c n = (Binary_c) copy();
61     n.right = right;
62     return n;
63     }
64
65     /** Get the precedence of the expression. */
66     public Precedence precedence() {
67     return this.precedence;
68     }
69
70     public Binary precedence(Precedence precedence) {
71     Binary_c n = (Binary_c) copy();
72     n.precedence = precedence;
73     return n;
74     }
75
76     /** Reconstruct the expression. */
77     protected Binary_c reconstruct(Expr left, Expr right) {
78     if (left != this.left || right != this.right) {
79         Binary_c n = (Binary_c) copy();
80         n.left = left;
81         n.right = right;
82         return n;
83     }
84
85     return this;
86     }
87
88     /** Visit the children of the expression. */
89     public Node visitChildren(NodeVisitor v) {
90     Expr left = (Expr) visitChild(this.left, v);
91     Expr right = (Expr) visitChild(this.right, v);
92     return reconstruct(left, right);
93     }
94     
95     public boolean isConstant() {
96     return left.isConstant() && right.isConstant();
97     }
98     
99     public Object JavaDoc constantValue() {
100         Object JavaDoc lv = left.constantValue();
101         Object JavaDoc rv = right.constantValue();
102
103     if (! isConstant()) {
104         return null;
105     }
106
107         if (op == ADD && (lv instanceof String JavaDoc || rv instanceof String JavaDoc)) {
108             // toString() does what we want for String, Number, and Boolean
109
if (lv == null) lv = "null";
110         if (rv == null) rv = "null";
111             return lv.toString() + rv.toString();
112     }
113
114         if (op == EQ && (lv instanceof String JavaDoc && rv instanceof String JavaDoc)) {
115             return Boolean.valueOf(((String JavaDoc) lv).intern() == ((String JavaDoc) rv).intern());
116         }
117
118         if (op == NE && (lv instanceof String JavaDoc && rv instanceof String JavaDoc)) {
119             return Boolean.valueOf(((String JavaDoc) lv).intern() != ((String JavaDoc) rv).intern());
120         }
121
122         // promote chars to ints.
123
if (lv instanceof Character JavaDoc) {
124             lv = new Integer JavaDoc(((Character JavaDoc) lv).charValue());
125         }
126
127         if (rv instanceof Character JavaDoc) {
128             rv = new Integer JavaDoc(((Character JavaDoc) rv).charValue());
129         }
130
131         try {
132             if (lv instanceof Number JavaDoc && rv instanceof Number JavaDoc) {
133                 if (lv instanceof Double JavaDoc || rv instanceof Double JavaDoc) {
134                     double l = ((Number JavaDoc) lv).doubleValue();
135                     double r = ((Number JavaDoc) rv).doubleValue();
136                     if (op == ADD) return new Double JavaDoc(l + r);
137                     if (op == SUB) return new Double JavaDoc(l - r);
138                     if (op == MUL) return new Double JavaDoc(l * r);
139                     if (op == DIV) return new Double JavaDoc(l / r);
140                     if (op == MOD) return new Double JavaDoc(l % r);
141                     if (op == EQ) return Boolean.valueOf(l == r);
142                     if (op == NE) return Boolean.valueOf(l != r);
143                     if (op == LT) return Boolean.valueOf(l < r);
144                     if (op == LE) return Boolean.valueOf(l <= r);
145                     if (op == GE) return Boolean.valueOf(l >= r);
146                     if (op == GT) return Boolean.valueOf(l > r);
147                     return null;
148                 }
149
150                 if (lv instanceof Float JavaDoc || rv instanceof Float JavaDoc) {
151                     float l = ((Number JavaDoc) lv).floatValue();
152                     float r = ((Number JavaDoc) rv).floatValue();
153                     if (op == ADD) return new Float JavaDoc(l + r);
154                     if (op == SUB) return new Float JavaDoc(l - r);
155                     if (op == MUL) return new Float JavaDoc(l * r);
156                     if (op == DIV) return new Float JavaDoc(l / r);
157                     if (op == MOD) return new Float JavaDoc(l % r);
158                     if (op == EQ) return Boolean.valueOf(l == r);
159                     if (op == NE) return Boolean.valueOf(l != r);
160                     if (op == LT) return Boolean.valueOf(l < r);
161                     if (op == LE) return Boolean.valueOf(l <= r);
162                     if (op == GE) return Boolean.valueOf(l >= r);
163                     if (op == GT) return Boolean.valueOf(l > r);
164                     return null;
165                 }
166
167                 if (lv instanceof Long JavaDoc && rv instanceof Number JavaDoc) {
168                     long l = ((Long JavaDoc) lv).longValue();
169                     long r = ((Number JavaDoc) rv).longValue();
170                     if (op == SHL) return new Long JavaDoc(l << r);
171                     if (op == SHR) return new Long JavaDoc(l >> r);
172                     if (op == USHR) return new Long JavaDoc(l >>> r);
173                 }
174
175                 if (lv instanceof Long JavaDoc || rv instanceof Long JavaDoc) {
176                     long l = ((Number JavaDoc) lv).longValue();
177                     long r = ((Number JavaDoc) rv).longValue();
178                     if (op == ADD) return new Long JavaDoc(l + r);
179                     if (op == SUB) return new Long JavaDoc(l - r);
180                     if (op == MUL) return new Long JavaDoc(l * r);
181                     if (op == DIV) return new Long JavaDoc(l / r);
182                     if (op == MOD) return new Long JavaDoc(l % r);
183                     if (op == EQ) return Boolean.valueOf(l == r);
184                     if (op == NE) return Boolean.valueOf(l != r);
185                     if (op == LT) return Boolean.valueOf(l < r);
186                     if (op == LE) return Boolean.valueOf(l <= r);
187                     if (op == GE) return Boolean.valueOf(l >= r);
188                     if (op == GT) return Boolean.valueOf(l > r);
189                     if (op == BIT_AND) return new Long JavaDoc(l & r);
190                     if (op == BIT_OR) return new Long JavaDoc(l | r);
191                     if (op == BIT_XOR) return new Long JavaDoc(l ^ r);
192                     return null;
193                 }
194
195                 // At this point, both lv and rv must be ints.
196
int l = ((Number JavaDoc) lv).intValue();
197                 int r = ((Number JavaDoc) rv).intValue();
198
199                 if (op == ADD) return new Integer JavaDoc(l + r);
200                 if (op == SUB) return new Integer JavaDoc(l - r);
201                 if (op == MUL) return new Integer JavaDoc(l * r);
202                 if (op == DIV) return new Integer JavaDoc(l / r);
203                 if (op == MOD) return new Integer JavaDoc(l % r);
204                 if (op == EQ) return Boolean.valueOf(l == r);
205                 if (op == NE) return Boolean.valueOf(l != r);
206                 if (op == LT) return Boolean.valueOf(l < r);
207                 if (op == LE) return Boolean.valueOf(l <= r);
208                 if (op == GE) return Boolean.valueOf(l >= r);
209                 if (op == GT) return Boolean.valueOf(l > r);
210                 if (op == BIT_AND) return new Integer JavaDoc(l & r);
211                 if (op == BIT_OR) return new Integer JavaDoc(l | r);
212                 if (op == BIT_XOR) return new Integer JavaDoc(l ^ r);
213                 if (op == SHL) return new Integer JavaDoc(l << r);
214                 if (op == SHR) return new Integer JavaDoc(l >> r);
215                 if (op == USHR) return new Integer JavaDoc(l >>> r);
216                 return null;
217             }
218         }
219         catch (ArithmeticException JavaDoc e) {
220             // ignore div by 0
221
return null;
222         }
223
224         if (lv instanceof Boolean JavaDoc && rv instanceof Boolean JavaDoc) {
225             boolean l = ((Boolean JavaDoc) lv).booleanValue();
226             boolean r = ((Boolean JavaDoc) rv).booleanValue();
227
228             if (op == EQ) return Boolean.valueOf(l == r);
229             if (op == NE) return Boolean.valueOf(l != r);
230             if (op == BIT_AND) return Boolean.valueOf(l & r);
231             if (op == BIT_OR) return Boolean.valueOf(l | r);
232             if (op == BIT_XOR) return Boolean.valueOf(l ^ r);
233             if (op == COND_AND) return Boolean.valueOf(l && r);
234             if (op == COND_OR) return Boolean.valueOf(l || r);
235         }
236
237         return null;
238     }
239
240     /** Type check the expression. */
241     public Node typeCheck(TypeChecker tc) throws SemanticException {
242         Type l = left.type();
243     Type r = right.type();
244
245     TypeSystem ts = tc.typeSystem();
246
247     if (op == GT || op == LT || op == GE || op == LE) {
248         if (! l.isNumeric()) {
249         throw new SemanticException("The " + op +
250             " operator must have numeric operands.", left.position());
251         }
252
253             if (! r.isNumeric()) {
254         throw new SemanticException("The " + op +
255             " operator must have numeric operands.", right.position());
256         }
257
258         return type(ts.Boolean());
259     }
260
261     if (op == EQ || op == NE) {
262             if (! ts.isCastValid(l, r) && ! ts.isCastValid(r, l)) {
263         throw new SemanticException("The " + op +
264             " operator must have operands of similar type.",
265             position());
266         }
267
268         return type(ts.Boolean());
269     }
270
271     if (op == COND_OR || op == COND_AND) {
272         if (! l.isBoolean()) {
273         throw new SemanticException("The " + op +
274             " operator must have boolean operands.", left.position());
275         }
276
277         if (! r.isBoolean()) {
278         throw new SemanticException("The " + op +
279             " operator must have boolean operands.", right.position());
280         }
281
282         return type(ts.Boolean());
283     }
284
285     if (op == ADD) {
286         if (ts.equals(l, ts.String()) || ts.equals(r, ts.String())) {
287                 if (!ts.canCoerceToString(r, tc.context())) {
288                     throw new SemanticException("Cannot coerce an expression " +
289                                 "of type " + r + " to a String.",
290                                 right.position());
291                 }
292                 if (!ts.canCoerceToString(l, tc.context())) {
293                     throw new SemanticException("Cannot coerce an expression " +
294                                 "of type " + l + " to a String.",
295                                 left.position());
296                 }
297                 return precedence(Precedence.STRING_ADD).type(ts.String());
298             }
299     }
300
301     if (op == BIT_AND || op == BIT_OR || op == BIT_XOR) {
302         if (l.isBoolean() && r.isBoolean()) {
303         return type(ts.Boolean());
304         }
305     }
306
307         if (op == ADD) {
308             if (! l.isNumeric()) {
309                 throw new SemanticException("The " + op +
310                     " operator must have numeric or String operands.",
311                     left.position());
312             }
313
314             if (! r.isNumeric()) {
315                 throw new SemanticException("The " + op +
316                     " operator must have numeric or String operands.",
317                     right.position());
318             }
319         }
320
321         if (op == BIT_AND || op == BIT_OR || op == BIT_XOR) {
322             if (! ts.isImplicitCastValid(l, ts.Long())) {
323                 throw new SemanticException("The " + op +
324                     " operator must have numeric or boolean operands.",
325                     left.position());
326             }
327
328             if (! ts.isImplicitCastValid(r, ts.Long())) {
329                 throw new SemanticException("The " + op +
330                     " operator must have numeric or boolean operands.",
331                     right.position());
332             }
333         }
334
335         if (op == SUB || op == MUL || op == DIV || op == MOD) {
336             if (! l.isNumeric()) {
337                 throw new SemanticException("The " + op +
338                     " operator must have numeric operands.", left.position());
339             }
340
341             if (! r.isNumeric()) {
342                 throw new SemanticException("The " + op +
343                     " operator must have numeric operands.", right.position());
344             }
345         }
346
347         if (op == SHL || op == SHR || op == USHR) {
348             if (! ts.isImplicitCastValid(l, ts.Long())) {
349                 throw new SemanticException("The " + op +
350                     " operator must have numeric operands.", left.position());
351             }
352
353             if (! ts.isImplicitCastValid(r, ts.Long())) {
354                 throw new SemanticException("The " + op +
355                     " operator must have numeric operands.", right.position());
356             }
357         }
358
359     if (op == SHL || op == SHR || op == USHR) {
360         // For shift, only promote the left operand.
361
return type(ts.promote(l));
362     }
363
364     return type(ts.promote(l, r));
365     }
366
367     public Type childExpectedType(Expr child, AscriptionVisitor av) {
368         Expr other;
369
370         if (child == left) {
371             other = right;
372         }
373         else if (child == right) {
374             other = left;
375         }
376         else {
377             return child.type();
378         }
379
380         TypeSystem ts = av.typeSystem();
381
382         try {
383             if (op == EQ || op == NE) {
384                 // Coercion to compatible types.
385
if ((child.type().isReference() || child.type().isNull()) &&
386                     (other.type().isReference() || other.type().isNull())) {
387                     return ts.leastCommonAncestor(child.type(), other.type());
388                 }
389
390                 if (child.type().isBoolean() && other.type().isBoolean()) {
391                     return ts.Boolean();
392                 }
393
394                 if (child.type().isNumeric() && other.type().isNumeric()) {
395                     return ts.promote(child.type(), other.type());
396                 }
397
398                 if (child.type().isImplicitCastValid(other.type())) {
399                     return other.type();
400                 }
401
402                 return child.type();
403             }
404
405             if (op == ADD && ts.equals(type, ts.String())) {
406                 // Implicit coercion to String.
407
return ts.String();
408             }
409
410             if (op == GT || op == LT || op == GE || op == LE) {
411                 if (child.type().isNumeric() && other.type().isNumeric()) {
412                     return ts.promote(child.type(), other.type());
413                 }
414
415                 return child.type();
416             }
417
418             if (op == COND_OR || op == COND_AND) {
419                 return ts.Boolean();
420             }
421
422             if (op == BIT_AND || op == BIT_OR || op == BIT_XOR) {
423                 if (other.type().isBoolean()) {
424                     return ts.Boolean();
425                 }
426
427                 if (child.type().isNumeric() && other.type().isNumeric()) {
428                     return ts.promote(child.type(), other.type());
429                 }
430
431                 return child.type();
432             }
433
434             if (op == ADD || op == SUB || op == MUL || op == DIV || op == MOD) {
435                 if (child.type().isNumeric() && other.type().isNumeric()) {
436                     Type t = ts.promote(child.type(), other.type());
437
438                     if (ts.isImplicitCastValid(t, av.toType())) {
439                         return t;
440                     }
441                     else {
442                         return av.toType();
443                     }
444                 }
445
446                 return child.type();
447             }
448
449             if (op == SHL || op == SHR || op == USHR) {
450                 if (child.type().isNumeric() && other.type().isNumeric()) {
451                     if (child == left) {
452                         Type t = ts.promote(child.type());
453
454                         if (ts.isImplicitCastValid(t, av.toType())) {
455                             return t;
456                         }
457                         else {
458                             return av.toType();
459                         }
460                     }
461                     else {
462                         return ts.promote(child.type());
463                     }
464                 }
465
466                 return child.type();
467             }
468
469             return child.type();
470         }
471         catch (SemanticException e) {
472         }
473
474         return child.type();
475     }
476
477     /** Get the throwsArithmeticException of the expression. */
478     public boolean throwsArithmeticException() {
479     // conservatively assume that any division or mod may throw
480
// ArithmeticException this is NOT true-- floats and doubles don't
481
// throw any exceptions ever...
482
return op == DIV || op == MOD;
483     }
484
485     public String JavaDoc toString() {
486     return left + " " + op + " " + right;
487     }
488
489     /** Write the expression to an output file. */
490     public void prettyPrint(CodeWriter w, PrettyPrinter tr) {
491     printSubExpr(left, true, w, tr);
492     w.write(" ");
493     w.write(op.toString());
494     w.allowBreak(type() == null || type().isPrimitive() ? 2 : 0, " ");
495     printSubExpr(right, false, w, tr);
496     }
497
498   public void dump(CodeWriter w) {
499     super.dump(w);
500
501     if (type != null) {
502       w.allowBreak(4, " ");
503       w.begin(0);
504       w.write("(type " + type + ")");
505       w.end();
506     }
507
508     w.allowBreak(4, " ");
509     w.begin(0);
510     w.write("(operator " + op + ")");
511     w.end();
512   }
513
514   public Term entry() {
515     return left.entry();
516   }
517
518   public List acceptCFG(CFGBuilder v, List succs) {
519     if (op == COND_AND || op == COND_OR) {
520       // short-circuit
521
if (left instanceof BooleanLit) {
522         BooleanLit b = (BooleanLit) left;
523         if ((b.value() && op == COND_OR) || (! b.value() && op == COND_AND)) {
524           v.visitCFG(left, this);
525         }
526         else {
527           v.visitCFG(left, right.entry());
528           v.visitCFG(right, this);
529         }
530       }
531       else {
532         if (op == COND_AND) {
533           // AND operator
534
// short circuit means that left is false
535
v.visitCFG(left, FlowGraph.EDGE_KEY_TRUE, right.entry(),
536                            FlowGraph.EDGE_KEY_FALSE, this);
537         }
538         else {
539           // OR operator
540
// short circuit means that left is true
541
v.visitCFG(left, FlowGraph.EDGE_KEY_FALSE, right.entry(),
542                            FlowGraph.EDGE_KEY_TRUE, this);
543         }
544         v.visitCFG(right, FlowGraph.EDGE_KEY_TRUE, this,
545                           FlowGraph.EDGE_KEY_FALSE, this);
546       }
547     }
548     else {
549       if (left.type().isBoolean() && right.type().isBoolean()) {
550           v.visitCFG(left, FlowGraph.EDGE_KEY_TRUE, right.entry(),
551                            FlowGraph.EDGE_KEY_FALSE, right.entry());
552           v.visitCFG(right, FlowGraph.EDGE_KEY_TRUE, this,
553                             FlowGraph.EDGE_KEY_FALSE, this);
554       }
555       else {
556           v.visitCFG(left, right.entry());
557           v.visitCFG(right, this);
558       }
559     }
560
561     return succs;
562   }
563
564   public List throwTypes(TypeSystem ts) {
565     if (throwsArithmeticException()) {
566       return Collections.singletonList(ts.ArithmeticException());
567     }
568
569     return Collections.EMPTY_LIST;
570   }
571 }
572
Popular Tags