aspect ConstantExpression { class Constant { private Number n; private boolean isBoolean = false; private boolean booleanValue; private boolean isString = false; private String stringValue; private boolean isChar = false; private char c; public boolean error = false; public Constant(char c) { isChar = true; this.c = c; } public Constant(Number n) { this.n = n; } public Constant(int i) { n = new Integer(i); } public Constant(long l) { n = new Long(l); } public Constant(float f) { n = new Float(f); } public Constant(double d) { n = new Double(d); } public Constant(boolean b) { isBoolean = true; booleanValue = b; } public Constant(String s) { isString = true; stringValue = s; } int intValue() { if(isChar) return c; if(!isBoolean && !isString) return n.intValue(); throw new UnsupportedOperationException(); } long longValue() { if(isChar) return c; if(!isBoolean && !isString) return n.longValue(); throw new UnsupportedOperationException(); } float floatValue() { if(isChar) return c; if(!isBoolean && !isString) return n.floatValue(); throw new UnsupportedOperationException(); } double doubleValue() { if(isChar) return c; if(!isBoolean && !isString) return n.doubleValue(); throw new UnsupportedOperationException(); } boolean booleanValue() { if(isBoolean) return booleanValue; throw new UnsupportedOperationException(); } String stringValue() { if(isString) return stringValue; if(isBoolean) return new Boolean(booleanValue).toString(); if(isChar) return new Character(c).toString(); return n.toString(); } } syn Constant Expr.constant() { throw new UnsupportedOperationException("ConstantExpression operation constant" + " not supported for type " + getClass().getName()); } syn lazy Constant VarAccess.constant() = decl().getAbstractVarInit().constant(); eq FieldDot.constant() = getRight().constant(); eq CastExpr.constant() = type().cast(getExpr().constant()); eq ParExpr.constant() = getExpr().constant(); syn lazy Constant Binary.constant(); eq PlusExpr.constant() = type().plus(getOperand().constant()); eq MinusExpr.constant() = type().minus(getOperand().constant()); eq BitNotExpr.constant() = type().bitNot(getOperand().constant()); eq MulExpr.constant() = type().mul(getLeftOperand().constant(), getRightOperand().constant()); eq DivExpr.constant() = type().div(getLeftOperand().constant(), getRightOperand().constant()); eq ModExpr.constant() = type().mod(getLeftOperand().constant(), getRightOperand().constant()); eq AddExpr.constant() = type().add(getLeftOperand().constant(), getRightOperand().constant()); eq SubExpr.constant() = type().sub(getLeftOperand().constant(), getRightOperand().constant()); eq LShiftExpr.constant() = type().lshift(getLeftOperand().constant(), getRightOperand().constant()); eq RShiftExpr.constant() = type().rshift(getLeftOperand().constant(), getRightOperand().constant()); eq URShiftExpr.constant() = type().urshift(getLeftOperand().constant(), getRightOperand().constant()); eq AndBitwiseExpr.constant() = type().andBitwise(getLeftOperand().constant(), getRightOperand().constant()); eq XorBitwiseExpr.constant() = type().xorBitwise(getLeftOperand().constant(), getRightOperand().constant()); eq OrBitwiseExpr.constant() = type().orBitwise(getLeftOperand().constant(), getRightOperand().constant()); eq QuestionColonExpr.constant() = type().questionColon(getCondition().constant(), getTrueExpr().constant(),getFalseExpr().constant()); syn lazy Constant AbstractVarInit.constant() { throw new UnsupportedOperationException(); } eq VarInit.constant() = getExpr().constant(); eq StringLiteralExpr.constant() = getStringLiteral().constant(); syn lazy boolean FPLiteral.isZero() { String s = getLITERAL(); for(int i = 0; i < s.length(); i++) { char c = s.charAt(i); if(c == 'E' || c == 'e') break; if(Character.isDigit(c) && c != '0') { return false; } } return true; } syn lazy boolean DoubleLiteral.isZero() { String s = getLITERAL(); for(int i = 0; i < s.length(); i++) { char c = s.charAt(i); if(c == 'E' || c == 'e') break; if(Character.isDigit(c) && c != '0') { return false; } } return true; } static long Literal.parseLong(String s) { long x = 0L; s = s.toLowerCase(); int radix = 10; boolean neg = false; if(s.startsWith("0x")) { radix = 16; s = s.substring(2); } else if(s.startsWith("0")) { radix = 8; s = s.substring(1); } else if(s.startsWith("-")) { s = s.substring(1); neg = true; } for (int i = 0; i < s.length(); i++) { int c = s.charAt(i); if (c < '0' || c > '9') { c = c - 'a' + 10; } else { c = c - '0'; } x *= radix; x += c; } if(radix == 10 && x == Long.MIN_VALUE) return x; if(radix == 10 && x < 0) { throw new NumberFormatException(""); } return neg ? -x : x; } syn boolean IntegerLiteral.isHex() = getLITERAL().toLowerCase().startsWith("0x"); syn boolean IntegerLiteral.isOctal() = getLITERAL().startsWith("0"); syn boolean IntegerLiteral.isDecimal() = !isHex() && !isOctal(); syn boolean LongLiteral.isHex() = getLITERAL().toLowerCase().startsWith("0x"); syn boolean LongLiteral.isOctal() = getLITERAL().startsWith("0"); syn boolean LongLiteral.isDecimal() = !isHex() && !isOctal(); rewrite MinusExpr { when(getOperand() instanceof IntegerLiteral && ((IntegerLiteral)getOperand()).isDecimal()) to IntegerLiteral new IntegerLiteral("-" + ((IntegerLiteral)getOperand()).getLITERAL()); } rewrite MinusExpr { when(getOperand() instanceof LongLiteral && ((LongLiteral)getOperand()).isDecimal()) to LongLiteral new LongLiteral("-" + ((LongLiteral)getOperand()).getLITERAL()); } eq IntegerLiteral.constant() { long l = 0; try { l = Literal.parseLong(getLITERAL()); } catch (NumberFormatException e) { } Constant c = new Constant((int)l); if(isDecimal() && l != (int)l) c.error = true; if(isOctal() && l > 037777777777L) c.error = true; return c; } eq LongLiteral.constant() { try { return new Constant(Literal.parseLong(getLITERAL())); } catch (NumberFormatException e) { Constant c = new Constant(0L); c.error = true; return c; } } eq FPLiteral.constant() { try { return new Constant(Float.parseFloat(getLITERAL())); } catch (NumberFormatException e) { Constant c = new Constant(0.0f); c.error = true; return c; } } eq DoubleLiteral.constant() { try { return new Constant(Double.parseDouble(getLITERAL())); } catch (NumberFormatException e) { Constant c = new Constant(0.0d); c.error = true; return c; } } eq BooleanLiteral.constant() = new Constant(Boolean.valueOf(getLITERAL()).booleanValue()); eq CharLiteral.constant() = new Constant(getLITERAL().charAt(0)); eq StringLiteral.constant() = new Constant(getLITERAL()); syn Constant TypeDecl.cast(Constant c) { throw new UnsupportedOperationException("ConstantExpression operation cast" + " not supported for type " + getClass().getName()); } eq IntegralType.cast(Constant c)= new Constant(c.intValue()); eq ShortType.cast(Constant c) = new Constant((short)c.intValue()); eq CharType.cast(Constant c) = new Constant((char)c.intValue()); eq ByteType.cast(Constant c) = new Constant((byte)c.intValue()); eq LongType.cast(Constant c) = new Constant(c.longValue()); eq FloatType.cast(Constant c) = new Constant(c.floatValue()); eq DoubleType.cast(Constant c) = new Constant(c.doubleValue()); eq BooleanType.cast(Constant c) = new Constant(c.booleanValue()); eq ClassDecl.cast(Constant c) = new Constant(c.stringValue()); syn Constant TypeDecl.plus(Constant c) { throw new UnsupportedOperationException("ConstantExpression operation plus" + " not supported for type " + getClass().getName()); } eq IntegralType.plus(Constant c) = c; eq LongType.plus(Constant c) = c; eq FloatType.plus(Constant c) = c; eq DoubleType.plus(Constant c) = c; syn Constant TypeDecl.minus(Constant c) { throw new UnsupportedOperationException("ConstantExpression operation minus" + " not supported for type " + getClass().getName()); } eq IntegralType.minus(Constant c) = new Constant(-c.intValue()); eq LongType.minus(Constant c) = new Constant(-c.longValue()); eq FloatType.minus(Constant c) = new Constant(-c.floatValue()); eq DoubleType.minus(Constant c) = new Constant(-c.doubleValue()); syn Constant TypeDecl.bitNot(Constant c) { throw new UnsupportedOperationException("ConstantExpression operation bitNot" + " not supported for type " + getClass().getName()); } eq IntegralType.bitNot(Constant c) = new Constant(~c.intValue()); eq LongType.bitNot(Constant c) = new Constant(~c.longValue()); syn Constant TypeDecl.mul(Constant c1, Constant c2) { throw new UnsupportedOperationException("ConstantExpression operation mul" + " not supported for type " + getClass().getName()); } eq IntegralType.mul(Constant c1, Constant c2) = new Constant(c1.intValue() * c2.intValue()); eq LongType.mul(Constant c1, Constant c2) = new Constant(c1.longValue() * c2.longValue()); eq FloatType.mul(Constant c1, Constant c2) = new Constant(c1.floatValue() * c2.floatValue()); eq DoubleType.mul(Constant c1, Constant c2) = new Constant(c1.doubleValue() * c2.doubleValue()); syn Constant TypeDecl.div(Constant c1, Constant c2) { throw new UnsupportedOperationException("ConstantExpression operation div" + " not supported for type " + getClass().getName()); } eq IntegralType.div(Constant c1, Constant c2) = new Constant(c1.intValue() / c2.intValue()); eq LongType.div(Constant c1, Constant c2) = new Constant(c1.longValue() / c2.longValue()); eq FloatType.div(Constant c1, Constant c2) = new Constant(c1.floatValue() / c2.floatValue()); eq DoubleType.div(Constant c1, Constant c2) = new Constant(c1.doubleValue() / c2.doubleValue()); syn Constant TypeDecl.mod(Constant c1, Constant c2) { throw new UnsupportedOperationException("ConstantExpression operation mod" + " not supported for type " + getClass().getName()); } eq IntegralType.mod(Constant c1, Constant c2) = new Constant(c1.intValue() % c2.intValue()); eq LongType.mod(Constant c1, Constant c2) = new Constant(c1.longValue() % c2.longValue()); eq FloatType.mod(Constant c1, Constant c2) = new Constant(c1.floatValue() % c2.floatValue()); eq DoubleType.mod(Constant c1, Constant c2) = new Constant(c1.doubleValue() % c2.doubleValue()); syn Constant TypeDecl.add(Constant c1, Constant c2) { throw new UnsupportedOperationException("ConstantExpression operation add" + " not supported for type " + getClass().getName()); } eq IntegralType.add(Constant c1, Constant c2) = new Constant(c1.intValue() + c2.intValue()); eq LongType.add(Constant c1, Constant c2) = new Constant(c1.longValue() + c2.longValue()); eq FloatType.add(Constant c1, Constant c2) = new Constant(c1.floatValue() + c2.floatValue()); eq DoubleType.add(Constant c1, Constant c2) = new Constant(c1.doubleValue() + c2.doubleValue()); eq ClassDecl.add(Constant c1, Constant c2) = new Constant(c1.stringValue() + c2.stringValue()); syn Constant TypeDecl.sub(Constant c1, Constant c2) { throw new UnsupportedOperationException("ConstantExpression operation sub" + " not supported for type " + getClass().getName()); } eq IntegralType.sub(Constant c1, Constant c2) = new Constant(c1.intValue() - c2.intValue()); eq LongType.sub(Constant c1, Constant c2) = new Constant(c1.longValue() - c2.longValue()); eq FloatType.sub(Constant c1, Constant c2) = new Constant(c1.floatValue() - c2.floatValue()); eq DoubleType.sub(Constant c1, Constant c2) = new Constant(c1.doubleValue() - c2.doubleValue()); syn Constant TypeDecl.lshift(Constant c1, Constant c2) { throw new UnsupportedOperationException("ConstantExpression operation lshift" + " not supported for type " + getClass().getName()); } eq IntegralType.lshift(Constant c1, Constant c2) = new Constant(c1.intValue() << c2.intValue()); eq LongType.lshift(Constant c1, Constant c2) = new Constant(c1.longValue() << c2.longValue()); syn Constant TypeDecl.rshift(Constant c1, Constant c2) { throw new UnsupportedOperationException("ConstantExpression operation rshift" + " not supported for type " + getClass().getName()); } eq IntegralType.rshift(Constant c1, Constant c2) = new Constant(c1.intValue() >> c2.intValue()); eq LongType.rshift(Constant c1, Constant c2) = new Constant(c1.longValue() >> c2.longValue()); syn Constant TypeDecl.urshift(Constant c1, Constant c2) { throw new UnsupportedOperationException("ConstantExpression operation urshift" + " not supported for type " + getClass().getName()); } eq IntegralType.urshift(Constant c1, Constant c2) = new Constant(c1.intValue() >>> c2.intValue()); eq LongType.urshift(Constant c1, Constant c2) = new Constant(c1.longValue() >>> c2.longValue()); syn Constant TypeDecl.andBitwise(Constant c1, Constant c2) { throw new UnsupportedOperationException("ConstantExpression operation andBitwise" + " not supported for type " + getClass().getName()); } eq IntegralType.andBitwise(Constant c1, Constant c2) = new Constant(c1.intValue() & c2.intValue()); eq LongType.andBitwise(Constant c1, Constant c2) = new Constant(c1.longValue() & c2.longValue()); eq BooleanType.andBitwise(Constant c1, Constant c2) = new Constant(c1.booleanValue() & c2.booleanValue()); syn Constant TypeDecl.xorBitwise(Constant c1, Constant c2) { throw new UnsupportedOperationException("ConstantExpression operation xorBitwise" + " not supported for type " + getClass().getName()); } eq IntegralType.xorBitwise(Constant c1, Constant c2) = new Constant(c1.intValue() ^ c2.intValue()); eq LongType.xorBitwise(Constant c1, Constant c2) = new Constant(c1.longValue() ^ c2.longValue()); eq BooleanType.xorBitwise(Constant c1, Constant c2) = new Constant(c1.booleanValue() ^ c2.booleanValue()); syn Constant TypeDecl.orBitwise(Constant c1, Constant c2) { throw new UnsupportedOperationException("ConstantExpression operation orBitwise" + " not supported for type " + getClass().getName()); } eq IntegralType.orBitwise(Constant c1, Constant c2) = new Constant(c1.intValue() | c2.intValue()); eq LongType.orBitwise(Constant c1, Constant c2) = new Constant(c1.longValue() | c2.longValue()); eq BooleanType.orBitwise(Constant c1, Constant c2) = new Constant(c1.booleanValue() | c2.booleanValue()); syn Constant TypeDecl.questionColon(Constant cond, Constant c1, Constant c2) { throw new UnsupportedOperationException("ConstantExpression operation questionColon" + " not supported for type " + getClass().getName()); } eq IntegralType.questionColon(Constant cond, Constant c1, Constant c2) = new Constant(cond.booleanValue() ? c1.intValue() : c2.intValue()); eq LongType.questionColon(Constant cond, Constant c1, Constant c2) = new Constant(cond.booleanValue() ? c1.longValue() : c2.longValue()); eq FloatType.questionColon(Constant cond, Constant c1, Constant c2) = new Constant(cond.booleanValue() ? c1.floatValue() : c2.floatValue()); eq DoubleType.questionColon(Constant cond, Constant c1, Constant c2) = new Constant(cond.booleanValue() ? c1.doubleValue() : c2.doubleValue()); eq BooleanType.questionColon(Constant cond, Constant c1, Constant c2) = new Constant(cond.booleanValue() ? c1.booleanValue() : c2.booleanValue()); eq ClassDecl.questionColon(Constant cond, Constant c1, Constant c2) = new Constant(cond.booleanValue() ? c1.stringValue() : c2.stringValue()); /* * representableIn(T) is true if and only if the the expression is a * compile-time constant of type byte, char, short or int, and the value * of the expression can be represented (by an expression) in the type T * where T must be byte, char or short. */ syn lazy boolean Expr.representableIn(TypeDecl t) { if (!type().isByte() && !type().isChar() && !type().isShort() && !type().isInt()) { return false; } if (t.isByte()) return constant().intValue() >= Byte.MIN_VALUE && constant().intValue() <= Byte.MAX_VALUE; if (t.isChar()) return constant().intValue() >= Character.MIN_VALUE && constant().intValue() <= Character.MAX_VALUE; if (t.isShort()) return constant().intValue() >= Short.MIN_VALUE && constant().intValue() <= Short.MAX_VALUE; if(t.isInt()) return constant().intValue() >= Integer.MIN_VALUE && constant().intValue() <= Integer.MAX_VALUE; return false; } syn lazy boolean AbstractVarInit.representableIn(TypeDecl t); eq VarInit.representableIn(TypeDecl t) = getExpr().representableIn(t); eq ArrayInit.representableIn(TypeDecl t) { for(int i = 0; i < getNumAbstractVarInit(); i++) if(!getAbstractVarInit(i).representableIn(t)) return false; return true; } // isConstant() syn boolean MemberDecl.isConstant() = false; eq FieldDeclaration.isConstant() = isFinal() && hasAbstractVarInit() && getAbstractVarInit().isConstant() && (type().isPrimitive() || type().isString()); syn lazy boolean Expr.isConstant() = false; eq Literal.isConstant() = true; eq NullLiteral.isConstant() = false; eq StringLiteralExpr.isConstant() = getStringLiteral().isConstant(); eq CastExpr.isConstant() = getExpr().isConstant() && (getTypeAccess().type().isPrimitive() || getTypeAccess().type().isString()); eq PlusExpr.isConstant() = getOperand().isConstant(); eq MinusExpr.isConstant() = getOperand().isConstant(); eq BitNotExpr.isConstant() = getOperand().isConstant(); eq LogNotExpr.isConstant() = getOperand().isConstant(); eq Binary.isConstant() = getLeftOperand().isConstant() && getRightOperand().isConstant(); eq InstanceOfExpr.isConstant() = false; eq QuestionColonExpr.isConstant() = getCondition().isConstant() && getTrueExpr().isConstant() && getFalseExpr().isConstant(); eq ParExpr.isConstant() = getExpr().isConstant(); eq AbstractDot.isConstant() = getRight().isConstant(); eq FieldDot.isConstant() = getRight().isConstant() && getLeft() instanceof TypeAccess; eq DivExpr.isConstant() = getLeftOperand().isConstant() && getRightOperand().isConstant() && !(getRightOperand().type().isInt() && getRightOperand().constant().intValue() == 0); eq ModExpr.isConstant() = getLeftOperand().isConstant() && getRightOperand().isConstant() && !(getRightOperand().type().isInt() && getRightOperand().constant().intValue() == 0); eq VarAccess.isConstant() { Variable v = decl(); return v.isFinal() && v.hasAbstractVarInit() && v.getAbstractVarInit().isConstant() && (v.type().isPrimitive() || v.type().isString()); } syn boolean AbstractVarInit.isConstant() = false; eq VarInit.isConstant() = getExpr().isConstant(); syn boolean Expr.isTrue() = isConstant() && type().isBoolean() && constant().booleanValue(); syn boolean Expr.isFalse() = isConstant() && type().isBoolean() && !constant().booleanValue(); syn Expr Binary.left() = getLeftOperand(); syn Expr Binary.right() = getRightOperand(); syn lazy TypeDecl Binary.binaryNumericPromotedType() { TypeDecl leftType = left().type(); TypeDecl rightType = right().type(); if(leftType.isString()) return leftType; if(rightType.isString()) return rightType; if(leftType.isNumericType() && rightType.isNumericType()) return ((NumericType)leftType).binaryNumericPromotion((NumericType)rightType); if(leftType.isBoolean() && rightType.isBoolean()) return leftType; return illegalType(); } syn char Expr.constantCharValue() = 0; eq CharLiteral.constantCharValue() = getLITERAL().charAt(0); eq LogNotExpr.constant() = new Constant(!getOperand().constant().booleanValue()); eq EQExpr.constant() = new Constant(binaryNumericPromotedType().eqIsTrue(left(), right())); eq NEExpr.constant() = new Constant(!binaryNumericPromotedType().eqIsTrue(left(), right())); eq LTExpr.constant() = new Constant(binaryNumericPromotedType().ltIsTrue(left(), right())); eq LEExpr.constant() = new Constant(binaryNumericPromotedType().leIsTrue(left(), right())); eq GTExpr.constant() = new Constant(!binaryNumericPromotedType().leIsTrue(left(), right())); eq GEExpr.constant() = new Constant(!binaryNumericPromotedType().ltIsTrue(left(), right())); eq AndLogicalExpr.constant() = new Constant(left().constant().booleanValue() && right().constant().booleanValue()); eq OrLogicalExpr.constant() = new Constant(left().constant().booleanValue() || right().constant().booleanValue()); syn boolean TypeDecl.eqIsTrue(Expr left, Expr right) { System.err.println("Evaluation eqIsTrue for unknown type: " + getClass().getName()); return false; } eq IntegralType.eqIsTrue(Expr left, Expr right) = left.constant().intValue() == right.constant().intValue(); eq LongType.eqIsTrue(Expr left, Expr right) = left.constant().longValue() == right.constant().longValue(); eq FloatType.eqIsTrue(Expr left, Expr right) = left.constant().floatValue() == right.constant().floatValue(); eq DoubleType.eqIsTrue(Expr left, Expr right) = left.constant().doubleValue() == right.constant().doubleValue(); eq BooleanType.eqIsTrue(Expr left, Expr right) = left.isTrue() && right.isTrue() || left.isFalse() && right.isFalse(); eq ClassDecl.eqIsTrue(Expr left, Expr right) = isString() && left.constant().stringValue().equals(right.constant().stringValue()); syn boolean TypeDecl.ltIsTrue(Expr left, Expr right) = false; eq IntegralType.ltIsTrue(Expr left, Expr right) = left.constant().intValue() < right.constant().intValue(); eq LongType.ltIsTrue(Expr left, Expr right) = left.constant().longValue() < right.constant().longValue(); eq FloatType.ltIsTrue(Expr left, Expr right) = left.constant().floatValue() < right.constant().floatValue(); eq DoubleType.ltIsTrue(Expr left, Expr right) = left.constant().doubleValue() < right.constant().doubleValue(); syn boolean TypeDecl.leIsTrue(Expr left, Expr right) = false; eq IntegralType.leIsTrue(Expr left, Expr right) = left.constant().intValue() <= right.constant().intValue(); eq LongType.leIsTrue(Expr left, Expr right) = left.constant().longValue() <= right.constant().longValue(); eq FloatType.leIsTrue(Expr left, Expr right) = left.constant().floatValue() <= right.constant().floatValue(); eq DoubleType.leIsTrue(Expr left, Expr right) = left.constant().doubleValue() <= right.constant().doubleValue(); }