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 }