001 /* Copyright 2000, 2001, Compaq Computer Corporation */
002
003 package javafe.tc;
004
005
006 import javafe.ast.*;
007 import javafe.util.*;
008
009
010 public class ConstantExpr {
011
012 // ----------------------------------------------------------------------
013
014 //@ requires t != null;
015 public static boolean constantValueFitsIn( Object val, PrimitiveType t ) {
016 if( val instanceof Integer || val instanceof Long ) {
017 long l = getLongConstant( val );
018 switch( t.getTag() ) {
019 case TagConstants.INTTYPE:
020 return Integer.MIN_VALUE <= l && l <= Integer.MAX_VALUE;
021 case TagConstants.SHORTTYPE:
022 return -0x8000 <= l && l <= 0x7fff;
023 case TagConstants.BYTETYPE:
024 return -0x80 <= l && l <= 0x7f;
025 case TagConstants.CHARTYPE:
026 return 0x0 <= l && l <= 0xffff;
027 default:
028 return false;
029 }
030 }
031 else
032 return false;
033 }
034
035
036 /** Evaluates a compile-time constant expression. Returns Integer,
037 * Long, Float, Double, Boolean, String or null (if the expression
038 * is not a constant.)
039
040 * The relation between the FlowInsensitiveChecks.getType(e),
041 * and the type of eval(e) is as follows:
042
043 * <PRE>
044 * getType(e) eval(e)
045 *
046 * boolean Boolean or null
047 * byte Integer or null (*)
048 * short Integer or null (*)
049 * char Integer or null (*)
050 * int Integer or null
051 * long Long or null
052 * float Float or null
053 * double Double or null
054 * String String or null
055 * </PRE>
056 *
057 * These will have been widened to int appropriately...
058 */
059
060 //@ requires e != null;
061 public static Object eval(Expr e) {
062
063 Type t = FlowInsensitiveChecks.getType( e );
064
065 //System.out.println("eval at "+Location.toString( e.getStartLoc() )+" type "+Types.printName(t) );
066
067 try {
068
069 switch( e.getTag() ) {
070
071 case TagConstants.PARENEXPR:
072 return eval( ((ParenExpr)e).expr );
073
074 case TagConstants.CONDEXPR:
075 {
076 CondExpr ce = (CondExpr)e;
077 Object val = eval(ce.test);
078 if( val!= null && val instanceof Boolean ) {
079 if( ((Boolean)val).booleanValue() )
080 return eval(ce.thn);
081 else
082 return eval(ce.els);
083 } else
084 return null;
085 }
086
087 case TagConstants.CASTEXPR:
088 {
089 CastExpr ce = (CastExpr)e;
090 Object val = eval(ce.expr);
091 if( val == null ) return null;
092
093 Type tsub = FlowInsensitiveChecks.getType(ce.expr);
094 if( Types.isSameType( t, tsub ) ) {
095 // Identity conversion
096 return val;
097 }
098 else if( Types.isSameType( t, Types.javaLangString() ) ) {
099 // convert to a string
100 return val.toString();
101 }
102 else if( Types.isIntegralType( t ) ) {
103 if( Types.isSameType( t, Types.longType ) ) {
104 if( Types.isFloatingPointType( tsub ) )
105 return new Long( (long)getDoubleConstant( val ) );
106 else if( Types.isIntegralType( tsub ) )
107 return new Long( getLongConstant( val ) );
108 else return null;
109 } else {
110 // Type uses Integer representation:
111
112 // First, get ce.expr's val as a widened int:
113 int ival;
114 if (Types.isFloatingPointType(tsub))
115 ival = (int)getDoubleConstant(val);
116 else if (Types.isIntegralType(tsub))
117 ival = (int)getLongConstant(val);
118 else return null;
119
120 // Do narrowing conversion if needed:
121 if (Types.isByteType(t))
122 ival = (byte)ival;
123 else if (Types.isShortType(t))
124 ival = (short)ival;
125 else if (Types.isCharType(t))
126 ival = (char)ival;
127
128 return new Integer(ival);
129 }
130 } else if( Types.isFloatingPointType( t ) ) {
131 if( Types.isSameType( t, Types.doubleType ) ) {
132 if( Types.isFloatingPointType( tsub ) )
133 return new Double( getDoubleConstant( val ) );
134 else if( Types.isIntegralType( tsub ) )
135 return new Double( getLongConstant( val ) );
136 else return null;
137 } else {
138 // Type is float
139
140 if( Types.isFloatingPointType( tsub ) )
141 return new Float( (float)getDoubleConstant( val ) );
142 else if( Types.isIntegralType( tsub ) )
143 return new Float( getLongConstant( val ) );
144 else return null;
145 }
146 } else {
147 Assert.fail("Bad cast");
148 return null; // dummy return
149 }
150 }
151
152 case TagConstants.FIELDACCESS:
153 {
154 FieldAccess fa = (FieldAccess)e;
155 // Assume fa.od is prepped, and decl is defined
156
157 VarInit init = fa.decl.init; //@ nowarn Null;
158
159 if(Modifiers.isFinal( fa.decl.modifiers )
160 && init != null
161 && init instanceof Expr ) {
162
163 TypeCheck.inst.makeFlowInsensitiveChecks()
164 .checkFieldDecl( fa.decl );
165 return eval( (Expr)fa.decl.init );
166 }
167 else
168 return null;
169 }
170
171 case TagConstants.VARIABLEACCESS:
172 {
173 VariableAccess lva = (VariableAccess)e;
174 if( lva.decl instanceof LocalVarDecl ) {
175 LocalVarDecl d = (LocalVarDecl)lva.decl;
176
177 if(Modifiers.isFinal( d.modifiers )
178 && d.init != null
179 && d.init instanceof Expr )
180 return eval( (Expr)d.init );
181 else
182 return null;
183 }
184 else
185 // refers to a formal parameter
186 return null;
187 }
188
189 default:
190 if( e instanceof LiteralExpr ) {
191 // System.out.println("eval: LiteralExpr: value="+((LiteralExpr)e).value);
192 return ((LiteralExpr)e).value;
193 }
194 else if( e instanceof UnaryExpr ) {
195
196 UnaryExpr ue = (UnaryExpr)e;
197 Object val = eval( ue.expr );
198 // System.out.println("eval: unary: op="+e.getTag()+" sub value="+val);
199 if( val==null ) return null;
200
201 if( Types.isSameType( t, Types.intType ) ) {
202 int i = getIntConstant( val );
203 switch( e.getTag() ) {
204 case TagConstants.UNARYADD:
205 return val;
206 case TagConstants.UNARYSUB:
207 return new Integer(-i);
208 case TagConstants.BITNOT:
209 return new Integer(~i);
210 default:
211 return null;
212 }
213 } else if( Types.isSameType( t, Types.longType ) ) {
214 long l = getLongConstant( val );
215 switch( e.getTag() ) {
216 case TagConstants.UNARYADD:
217 return val;
218 case TagConstants.UNARYSUB:
219 return new Long(-l);
220 case TagConstants.BITNOT:
221 return new Long(~l);
222 default:
223 return null;
224 }
225 } else if( Types.isSameType( t, Types.floatType ) ) {
226 float f = getFloatConstant( val );
227 switch( e.getTag() ) {
228 case TagConstants.UNARYADD:
229 return val;
230 case TagConstants.UNARYSUB:
231 return new Float(-f);
232 default:
233 return null;
234 }
235 } else if( Types.isSameType( t, Types.doubleType ) ) {
236 double d = getDoubleConstant( val );
237 switch( e.getTag() ) {
238 case TagConstants.UNARYADD:
239 return val;
240 case TagConstants.UNARYSUB:
241 return new Double(-d);
242 default:
243 return null;
244 }
245 } else if( Types.isBooleanType( t ) ) {
246 switch( e.getTag() ) {
247 case TagConstants.NOT:
248 return Boolean.valueOf( ! getBooleanConstant(val) );
249 default:
250 return null;
251 }
252 } else
253 return null;
254 }
255 else if( e instanceof BinaryExpr ) {
256
257 BinaryExpr be = (BinaryExpr) e;
258 Object lval = eval( be.left );
259 Object rval = eval( be.right );
260
261 if( lval==null || rval==null ) return null;
262
263 if( Types.isSameType( t, Types.intType ) )
264 return evalIntBinaryOp( e.getTag(), lval, rval );
265 else if( Types.isSameType( t, Types.longType ) )
266 return evalLongBinaryOp( e.getTag(), lval, rval );
267 else if( Types.isSameType( t, Types.floatType ) )
268 return evalFloatBinaryOp( e.getTag(), lval, rval );
269 else if( Types.isSameType( t, Types.doubleType ) )
270 return evalDoubleBinaryOp( e.getTag(), lval, rval );
271 else if( Types.isBooleanType( t ) )
272 return evalBooleanBinaryOp( e.getTag(), lval, rval );
273 else
274 return null;
275 }
276
277 return null;
278 }
279 } catch( ArithmeticException ex ) {
280 ErrorSet.error("Arithmetic exception ("+ex.getMessage()
281 +") in evaluating constant expression");
282 return null;
283 } catch( AssertionFailureException ex ) {
284 System.out.println("At "+Location.toString( e.getStartLoc() ));
285 throw ex;
286 }
287 }
288
289 // ----------------------------------------------------------------------
290
291 private static Object evalIntBinaryOp(int op,
292 Object leftVal,
293 Object rightVal )
294 throws ArithmeticException {
295
296 int x = getIntConstant(leftVal);
297 int y = getIntConstant(rightVal);
298
299 switch( op ) {
300 default:
301 return null;
302 case TagConstants.ADD: return new Integer(x+y);
303 case TagConstants.SUB: return new Integer(x-y);
304 case TagConstants.STAR: return new Integer(x*y);
305 case TagConstants.DIV: return new Integer(x/y); //@nowarn ZeroDiv;//caught
306 case TagConstants.MOD: return new Integer(x%y); //@nowarn ZeroDiv;//caught
307 case TagConstants.LSHIFT: return new Integer(x<<y);
308 case TagConstants.RSHIFT: return new Integer(x>>y);
309 case TagConstants.URSHIFT: return new Integer(x>>>y);
310 case TagConstants.LT: return Boolean.valueOf(x<y);
311 case TagConstants.LE: return Boolean.valueOf(x<=y);
312 case TagConstants.GT: return Boolean.valueOf(x>y);
313 case TagConstants.GE: return Boolean.valueOf(x>=y);
314 case TagConstants.EQ: return Boolean.valueOf(x==y);
315 case TagConstants.NE: return Boolean.valueOf(x != y);
316 case TagConstants.BITAND: return new Integer(x&y);
317 case TagConstants.BITOR: return new Integer(x|y);
318 case TagConstants.BITXOR: return new Integer(x^y);
319 }
320 }
321
322 private static Object evalLongBinaryOp(int op,
323 Object leftVal,
324 Object rightVal )
325 throws ArithmeticException {
326
327 long x = getLongConstant(leftVal);
328 long y = getLongConstant(rightVal);
329
330 switch( op ) {
331 default:
332 return null;
333 case TagConstants.ADD: return new Long(x+y);
334 case TagConstants.SUB: return new Long(x-y);
335 case TagConstants.STAR: return new Long(x*y);
336 case TagConstants.DIV: return new Long(x/y); //@ nowarn ZeroDiv;//caught
337 case TagConstants.MOD: return new Long(x%y); //@ nowarn ZeroDiv;//caught
338 case TagConstants.LSHIFT: return new Long(x<<y);
339 case TagConstants.RSHIFT: return new Long(x>>y);
340 case TagConstants.URSHIFT: return new Long(x>>>y);
341 case TagConstants.LT: return Boolean.valueOf(x<y);
342 case TagConstants.LE: return Boolean.valueOf(x<=y);
343 case TagConstants.GT: return Boolean.valueOf(x>y);
344 case TagConstants.GE: return Boolean.valueOf(x>=y);
345 case TagConstants.EQ: return Boolean.valueOf(x==y);
346 case TagConstants.NE: return Boolean.valueOf(x != y);
347 case TagConstants.BITAND: return new Long(x&y);
348 case TagConstants.BITOR: return new Long(x|y);
349 case TagConstants.BITXOR: return new Long(x^y);
350 }
351 }
352
353 private static Object evalBooleanBinaryOp(int op,
354 Object leftVal,
355 Object rightVal )
356 throws ArithmeticException {
357
358 if (leftVal instanceof Float || leftVal instanceof Double ||
359 rightVal instanceof Float || rightVal instanceof Double) {
360 return evalDoubleBinaryOp(op, leftVal, rightVal);
361 } else if (! (leftVal instanceof Boolean)) {
362 return evalLongBinaryOp(op, leftVal, rightVal);
363 }
364
365 boolean x = getBooleanConstant(leftVal);
366 boolean y = getBooleanConstant(rightVal);
367
368 switch( op ) {
369 default:
370 return null;
371 case TagConstants.EQ: return Boolean.valueOf(x==y);
372 case TagConstants.NE: return Boolean.valueOf(x != y);
373 case TagConstants.BITAND: return Boolean.valueOf(x&y);
374 case TagConstants.BITOR: return Boolean.valueOf(x|y);
375 case TagConstants.BITXOR: return Boolean.valueOf(x^y);
376 case TagConstants.AND: return Boolean.valueOf(x&&y);
377 case TagConstants.OR: return Boolean.valueOf(x||y);
378 }
379 }
380
381 private static Object evalFloatBinaryOp(int op,
382 Object leftVal,
383 Object rightVal ) {
384 float x = getFloatConstant(leftVal);
385 float y = getFloatConstant(rightVal);
386
387 switch( op ) {
388 default:
389 return null;
390 case TagConstants.ADD: return new Float(x+y);
391 case TagConstants.SUB: return new Float(x-y);
392 case TagConstants.STAR:return new Float(x*y);
393 case TagConstants.DIV: return new Float(x/y);
394 case TagConstants.MOD: return new Float(x%y);
395 case TagConstants.EQ: return Boolean.valueOf(x==y);
396 case TagConstants.NE: return Boolean.valueOf(x != y);
397 case TagConstants.LT: return Boolean.valueOf(x<y);
398 case TagConstants.LE: return Boolean.valueOf(x<=y);
399 case TagConstants.GT: return Boolean.valueOf(x>y);
400 case TagConstants.GE: return Boolean.valueOf(x>=y);
401 }
402 }
403
404 private static Object evalDoubleBinaryOp(int op,
405 Object leftVal,
406 Object rightVal ) {
407 double x = getDoubleConstant(leftVal);
408 double y = getDoubleConstant(rightVal);
409
410 switch( op ) {
411 default:
412 return null;
413 case TagConstants.ADD: return new Double(x+y);
414 case TagConstants.SUB: return new Double(x-y);
415 case TagConstants.STAR:return new Double(x*y);
416 case TagConstants.DIV: return new Double(x/y);
417 case TagConstants.MOD: return new Double(x%y);
418 case TagConstants.EQ: return Boolean.valueOf(x==y);
419 case TagConstants.NE: return Boolean.valueOf(x != y);
420 case TagConstants.LT: return Boolean.valueOf(x<y);
421 case TagConstants.LE: return Boolean.valueOf(x<=y);
422 case TagConstants.GT: return Boolean.valueOf(x>y);
423 case TagConstants.GE: return Boolean.valueOf(x>=y);
424 }
425 }
426
427 // ----------------------------------------------------------------------
428
429 public static int getIntConstant(Object c) {
430 if( c instanceof Integer )
431 return ((Integer)c).intValue();
432 else {
433 Assert.fail("Bad getIntConstant");
434 return 0; // dummy return
435 }
436 }
437
438 public static long getLongConstant(Object c) {
439 if( c instanceof Long )
440 return ((Long)c).longValue();
441 else if( c instanceof Integer )
442 return ((Integer)c).intValue();
443 else {
444 Assert.fail("Bad getLongConstant: "+c);
445 return 0; // dummy return
446 }
447 }
448
449 private static boolean getBooleanConstant(Object c) {
450 if( c instanceof Boolean )
451 return ((Boolean)c).booleanValue();
452 else {
453 Assert.fail("Bad getBooleanConstant");
454 return false; // dummy return
455 }
456 }
457
458 private static float getFloatConstant(Object c) {
459 if( c instanceof Integer )
460 return ((Integer)c).intValue();
461 else if( c instanceof Long )
462 return ((Long)c).longValue();
463 else if( c instanceof Float )
464 return ((Float)c).floatValue();
465 else {
466 Assert.fail("Bad getFloatConstant");
467 return 0; // dummy return
468 }
469 }
470
471 private static double getDoubleConstant(Object c) {
472 if( c instanceof Integer )
473 return ((Integer)c).intValue();
474 else if( c instanceof Long )
475 return ((Long)c).longValue();
476 else if( c instanceof Float )
477 return ((Float)c).floatValue();
478 else if( c instanceof Double )
479 return ((Double)c).doubleValue();
480 else {
481 Assert.fail("Bad getDoubleConstant");
482 return 0; // dummy return
483 }
484 }
485 }