001    /* Copyright (c) 2005-2008, Torbjorn Ekman
002     * All rights reserved.
003     *
004     * Redistribution and use in source and binary forms, with or without
005     * modification, are permitted provided that the following conditions are met:
006     *
007     * 1. Redistributions of source code must retain the above copyright notice,
008     * this list of conditions and the following disclaimer.
009     *
010     * 2. Redistributions in binary form must reproduce the above copyright notice,
011     * this list of conditions and the following disclaimer in the documentation
012     * and/or other materials provided with the distribution.
013     *
014     * 3. Neither the name of the copyright holder nor the names of its
015     * contributors may be used to endorse or promote products derived from this
016     * software without specific prior written permission.
017     *
018     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
021     * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
022     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
023     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
024     * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
025     * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
026     * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
027     * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
028     * POSSIBILITY OF SUCH DAMAGE.
029     */
030    
031    aspect ConstantExpression {
032      syn Constant Expr.constant() {
033        throw new UnsupportedOperationException("ConstantExpression operation constant"
034            + " not supported for type " + getClass().getName());
035      }
036      // enable caching for Literal constants
037      syn lazy Constant Literal.constant() {
038        throw new UnsupportedOperationException("ConstantExpression operation constant"
039            + " not supported for type " + getClass().getName());
040      }
041    
042      eq VarAccess.constant() = type().cast(decl().getInit().constant());
043      eq AbstractDot.constant() = lastAccess().constant();
044      eq CastExpr.constant() = type().cast(getExpr().constant());
045      eq ParExpr.constant() = getExpr().constant();
046    
047      eq PlusExpr.constant() = type().plus(getOperand().constant());
048      eq MinusExpr.constant() = type().minus(getOperand().constant());
049      eq BitNotExpr.constant() = type().bitNot(getOperand().constant());
050    
051      eq MulExpr.constant() = type().mul(getLeftOperand().constant(), getRightOperand().constant());
052      eq DivExpr.constant() = type().div(getLeftOperand().constant(), getRightOperand().constant());
053      eq ModExpr.constant() = type().mod(getLeftOperand().constant(), getRightOperand().constant());
054    
055      eq AddExpr.constant() = type().add(getLeftOperand().constant(), getRightOperand().constant());
056      eq SubExpr.constant() = type().sub(getLeftOperand().constant(), getRightOperand().constant());
057    
058      eq LShiftExpr.constant() = type().lshift(getLeftOperand().constant(), getRightOperand().constant());
059      eq RShiftExpr.constant() = type().rshift(getLeftOperand().constant(), getRightOperand().constant());
060      eq URShiftExpr.constant() = type().urshift(getLeftOperand().constant(), getRightOperand().constant());
061    
062      eq AndBitwiseExpr.constant() = type().andBitwise(getLeftOperand().constant(), getRightOperand().constant());
063      eq XorBitwiseExpr.constant() = type().xorBitwise(getLeftOperand().constant(), getRightOperand().constant());
064      eq OrBitwiseExpr.constant() = type().orBitwise(getLeftOperand().constant(), getRightOperand().constant());
065    
066      syn lazy Constant ConditionalExpr.constant() = type().questionColon(getCondition().constant(), getTrueExpr().constant(),getFalseExpr().constant());
067    
068      eq BooleanLiteral.constant() = Constant.create(Boolean.valueOf(getLITERAL()).booleanValue());
069      eq CharacterLiteral.constant() = Constant.create(getLITERAL().charAt(0));
070      eq StringLiteral.constant() = Constant.create(getLITERAL());
071    
072      syn Constant TypeDecl.cast(Constant c) {
073        throw new UnsupportedOperationException("ConstantExpression operation cast"
074            + " not supported for type " + getClass().getName());
075      }
076      eq IntegralType.cast(Constant c)= Constant.create(c.intValue());
077      eq ShortType.cast(Constant c) = Constant.create((short) c.intValue());
078      eq CharType.cast(Constant c) = Constant.create((char) c.intValue());
079      eq ByteType.cast(Constant c) = Constant.create((byte) c.intValue());
080      eq LongType.cast(Constant c) = Constant.create(c.longValue());
081      eq FloatType.cast(Constant c) = Constant.create(c.floatValue());
082      eq DoubleType.cast(Constant c) = Constant.create(c.doubleValue());
083      eq BooleanType.cast(Constant c) = Constant.create(c.booleanValue());
084      eq ClassDecl.cast(Constant c) = Constant.create(c.stringValue());
085    
086      syn Constant TypeDecl.plus(Constant c) {
087        throw new UnsupportedOperationException("ConstantExpression operation plus"
088            + " not supported for type " + getClass().getName());
089      }
090      eq IntegralType.plus(Constant c) = c;
091      eq LongType.plus(Constant c) = c;
092      eq FloatType.plus(Constant c) = c;
093      eq DoubleType.plus(Constant c) = c;
094    
095      syn Constant TypeDecl.minus(Constant c) {
096        throw new UnsupportedOperationException("ConstantExpression operation minus"
097            + " not supported for type " + getClass().getName());
098      }
099      eq IntegralType.minus(Constant c) = Constant.create(-c.intValue());
100      eq LongType.minus(Constant c) = Constant.create(-c.longValue());
101      eq FloatType.minus(Constant c) = Constant.create(-c.floatValue());
102      eq DoubleType.minus(Constant c) = Constant.create(-c.doubleValue());
103    
104      syn Constant TypeDecl.bitNot(Constant c) {
105        throw new UnsupportedOperationException("ConstantExpression operation bitNot"
106            + " not supported for type " + getClass().getName());
107      }
108      eq IntegralType.bitNot(Constant c) = Constant.create(~c.intValue());
109      eq LongType.bitNot(Constant c) = Constant.create(~c.longValue());
110    
111      syn Constant TypeDecl.mul(Constant c1, Constant c2) {
112        throw new UnsupportedOperationException("ConstantExpression operation mul"
113            + " not supported for type " + getClass().getName());
114      }
115      eq IntegralType.mul(Constant c1, Constant c2) = Constant.create(c1.intValue() * c2.intValue());
116      eq LongType.mul(Constant c1, Constant c2) = Constant.create(c1.longValue() * c2.longValue());
117      eq FloatType.mul(Constant c1, Constant c2) = Constant.create(c1.floatValue() * c2.floatValue());
118      eq DoubleType.mul(Constant c1, Constant c2) = Constant.create(c1.doubleValue() * c2.doubleValue());
119    
120      syn Constant TypeDecl.div(Constant c1, Constant c2) {
121        throw new UnsupportedOperationException("ConstantExpression operation div"
122            + " not supported for type " + getClass().getName());
123      }
124      eq IntegralType.div(Constant c1, Constant c2) = Constant.create(c1.intValue() / c2.intValue());
125      eq LongType.div(Constant c1, Constant c2) = Constant.create(c1.longValue() / c2.longValue());
126      eq FloatType.div(Constant c1, Constant c2) = Constant.create(c1.floatValue() / c2.floatValue());
127      eq DoubleType.div(Constant c1, Constant c2) = Constant.create(c1.doubleValue() / c2.doubleValue());
128    
129      syn Constant TypeDecl.mod(Constant c1, Constant c2) {
130        throw new UnsupportedOperationException("ConstantExpression operation mod"
131            + " not supported for type " + getClass().getName());
132      }
133      eq IntegralType.mod(Constant c1, Constant c2) = Constant.create(c1.intValue() % c2.intValue());
134      eq LongType.mod(Constant c1, Constant c2) = Constant.create(c1.longValue() % c2.longValue());
135      eq FloatType.mod(Constant c1, Constant c2) = Constant.create(c1.floatValue() % c2.floatValue());
136      eq DoubleType.mod(Constant c1, Constant c2) = Constant.create(c1.doubleValue() % c2.doubleValue());
137    
138      syn Constant TypeDecl.add(Constant c1, Constant c2) {
139        throw new UnsupportedOperationException("ConstantExpression operation add"
140            + " not supported for type " + getClass().getName());
141      }
142      eq IntegralType.add(Constant c1, Constant c2) = Constant.create(c1.intValue() + c2.intValue());
143      eq LongType.add(Constant c1, Constant c2) = Constant.create(c1.longValue() + c2.longValue());
144      eq FloatType.add(Constant c1, Constant c2) = Constant.create(c1.floatValue() + c2.floatValue());
145      eq DoubleType.add(Constant c1, Constant c2) = Constant.create(c1.doubleValue() + c2.doubleValue());
146      eq ClassDecl.add(Constant c1, Constant c2) = Constant.create(c1.stringValue() + c2.stringValue());
147    
148      syn Constant TypeDecl.sub(Constant c1, Constant c2) {
149        throw new UnsupportedOperationException("ConstantExpression operation sub"
150            + " not supported for type " + getClass().getName());
151      }
152      eq IntegralType.sub(Constant c1, Constant c2) = Constant.create(c1.intValue() - c2.intValue());
153      eq LongType.sub(Constant c1, Constant c2) = Constant.create(c1.longValue() - c2.longValue());
154      eq FloatType.sub(Constant c1, Constant c2) = Constant.create(c1.floatValue() - c2.floatValue());
155      eq DoubleType.sub(Constant c1, Constant c2) = Constant.create(c1.doubleValue() - c2.doubleValue());
156    
157      syn Constant TypeDecl.lshift(Constant c1, Constant c2) {
158        throw new UnsupportedOperationException("ConstantExpression operation lshift"
159            + " not supported for type " + getClass().getName());
160      }
161      eq IntegralType.lshift(Constant c1, Constant c2) = Constant.create(c1.intValue() << c2.intValue());
162      eq LongType.lshift(Constant c1, Constant c2) = Constant.create(c1.longValue() << c2.longValue());
163    
164      syn Constant TypeDecl.rshift(Constant c1, Constant c2) {
165        throw new UnsupportedOperationException("ConstantExpression operation rshift"
166            + " not supported for type " + getClass().getName());
167      }
168      eq IntegralType.rshift(Constant c1, Constant c2) = Constant.create(c1.intValue() >> c2.intValue());
169      eq LongType.rshift(Constant c1, Constant c2) = Constant.create(c1.longValue() >> c2.longValue());
170    
171      syn Constant TypeDecl.urshift(Constant c1, Constant c2) {
172        throw new UnsupportedOperationException("ConstantExpression operation urshift"
173            + " not supported for type " + getClass().getName());
174      }
175      eq IntegralType.urshift(Constant c1, Constant c2) = Constant.create(c1.intValue() >>> c2.intValue());
176      eq LongType.urshift(Constant c1, Constant c2) = Constant.create(c1.longValue() >>> c2.longValue());
177    
178      syn Constant TypeDecl.andBitwise(Constant c1, Constant c2) {
179        throw new UnsupportedOperationException("ConstantExpression operation andBitwise"
180            + " not supported for type " + getClass().getName());
181      }
182      eq IntegralType.andBitwise(Constant c1, Constant c2) = Constant.create(c1.intValue() & c2.intValue());
183      eq LongType.andBitwise(Constant c1, Constant c2) = Constant.create(c1.longValue() & c2.longValue());
184      eq BooleanType.andBitwise(Constant c1, Constant c2) = Constant.create(c1.booleanValue() & c2.booleanValue());
185    
186      syn Constant TypeDecl.xorBitwise(Constant c1, Constant c2) {
187        throw new UnsupportedOperationException("ConstantExpression operation xorBitwise"
188            + " not supported for type " + getClass().getName());
189      }
190      eq IntegralType.xorBitwise(Constant c1, Constant c2) = Constant.create(c1.intValue() ^ c2.intValue());
191      eq LongType.xorBitwise(Constant c1, Constant c2) = Constant.create(c1.longValue() ^ c2.longValue());
192      eq BooleanType.xorBitwise(Constant c1, Constant c2) = Constant.create(c1.booleanValue() ^ c2.booleanValue());
193    
194      syn Constant TypeDecl.orBitwise(Constant c1, Constant c2) {
195        throw new UnsupportedOperationException("ConstantExpression operation orBitwise"
196            + " not supported for type " + getClass().getName());
197      }
198      eq IntegralType.orBitwise(Constant c1, Constant c2) = Constant.create(c1.intValue() | c2.intValue());
199      eq LongType.orBitwise(Constant c1, Constant c2) = Constant.create(c1.longValue() | c2.longValue());
200      eq BooleanType.orBitwise(Constant c1, Constant c2) = Constant.create(c1.booleanValue() | c2.booleanValue());
201    
202      syn Constant TypeDecl.questionColon(Constant cond, Constant c1, Constant c2) {
203        throw new UnsupportedOperationException("ConstantExpression operation questionColon"
204            + " not supported for type " + getClass().getName());
205      }
206      eq IntegralType.questionColon(Constant cond, Constant c1, Constant c2) = Constant.create(cond.booleanValue() ? c1.intValue() : c2.intValue());
207      eq LongType.questionColon(Constant cond, Constant c1, Constant c2) = Constant.create(cond.booleanValue() ? c1.longValue() : c2.longValue());
208      eq FloatType.questionColon(Constant cond, Constant c1, Constant c2) = Constant.create(cond.booleanValue() ? c1.floatValue() : c2.floatValue());
209      eq DoubleType.questionColon(Constant cond, Constant c1, Constant c2) = Constant.create(cond.booleanValue() ? c1.doubleValue() : c2.doubleValue());
210      eq BooleanType.questionColon(Constant cond, Constant c1, Constant c2) = Constant.create(cond.booleanValue() ? c1.booleanValue() : c2.booleanValue());
211      eq ClassDecl.questionColon(Constant cond, Constant c1, Constant c2) = Constant.create(cond.booleanValue() ? c1.stringValue() : c2.stringValue());
212    
213      /*
214       * representableIn(T) is true if and only if the the expression is a
215       * compile-time constant of type byte, char, short or int, and the value
216       * of the expression can be represented (by an expression) in the type T
217       * where T must be byte, char or short.
218       */
219    
220      syn boolean Expr.representableIn(TypeDecl t) {
221        if (!type().isByte() && !type().isChar() && !type().isShort() && !type().isInt()) {
222          return false;
223        }
224        if (t.isByte()) {
225          return constant().intValue() >= Byte.MIN_VALUE && constant().intValue() <= Byte.MAX_VALUE;
226        }
227        if (t.isChar()) {
228          return constant().intValue() >= Character.MIN_VALUE && constant().intValue() <= Character.MAX_VALUE;
229        }
230        if (t.isShort()) {
231          return constant().intValue() >= Short.MIN_VALUE && constant().intValue() <= Short.MAX_VALUE;
232        }
233        if (t.isInt()) {
234          return constant().intValue() >= Integer.MIN_VALUE && constant().intValue() <= Integer.MAX_VALUE;
235        }
236        return false;
237      }
238    
239      eq ArrayInit.representableIn(TypeDecl t) {
240        for (int i = 0; i < getNumInit(); i++) {
241          if (!getInit(i).representableIn(t)) {
242            return false;
243          }
244        }
245        return true;
246      }
247    
248      // isConstant()
249    
250      syn boolean MemberDecl.isConstant() = false;
251      eq FieldDeclaration.isConstant() = isFinal() && hasInit() && getInit().isConstant() && (type() instanceof PrimitiveType || type().isString());
252    
253    
254      syn boolean Expr.isConstant() = false;
255      eq Literal.isConstant() = true;
256      eq NullLiteral.isConstant() = false;
257      eq CastExpr.isConstant() = getExpr().isConstant() &&
258        (getTypeAccess().type().isPrimitive() || getTypeAccess().type().isString());
259      eq PlusExpr.isConstant() = getOperand().isConstant();
260      eq MinusExpr.isConstant() = getOperand().isConstant();
261      eq BitNotExpr.isConstant() = getOperand().isConstant();
262      eq LogNotExpr.isConstant() = getOperand().isConstant();
263      syn lazy boolean Binary.isConstant() circular [false] = getLeftOperand().isConstant() && getRightOperand().isConstant();
264      eq InstanceOfExpr.isConstant() = false;
265      syn lazy boolean ConditionalExpr.isConstant() = getCondition().isConstant() && getTrueExpr().isConstant() && getFalseExpr().isConstant();
266      eq ParExpr.isConstant() = getExpr().isConstant();
267      eq AbstractDot.isConstant() = lastAccess().isConstant();
268    
269      eq DivExpr.isConstant() = getLeftOperand().isConstant() && getRightOperand().isConstant() && !(getRightOperand().type().isInt() && getRightOperand().constant().intValue() == 0);
270      eq ModExpr.isConstant() = getLeftOperand().isConstant() && getRightOperand().isConstant() && !(getRightOperand().type().isInt() && getRightOperand().constant().intValue() == 0);
271    
272      syn lazy boolean VarAccess.isConstant() circular [false] {
273        Variable v = decl();
274        if (v instanceof FieldDeclaration) {
275          FieldDeclaration f = (FieldDeclaration) v;
276          return f.isConstant() && (!isQualified() || (isQualified() && qualifier().isTypeAccess()));
277        }
278        boolean result = v.isFinal() && v.hasInit() && v.getInit().isConstant() && (v.type().isPrimitive() || v.type().isString());
279        return result && (!isQualified() || (isQualified() && qualifier().isTypeAccess()));
280      }
281    
282      // BooleanType is used to discard UnknownType which also responds true for isBoolean()
283      syn boolean Expr.isTrue() = isConstant() && type() instanceof BooleanType && constant().booleanValue();
284      syn boolean Expr.isFalse() = isConstant() && type() instanceof BooleanType && !constant().booleanValue();
285    
286      eq ParExpr.isTrue() = getExpr().isTrue();
287      eq Literal.isTrue() = false;
288      eq BooleanLiteral.isTrue() = constant().booleanValue();
289      eq LogNotExpr.isTrue() = getOperand().isFalse();
290    
291      eq ParExpr.isFalse() = getExpr().isFalse();
292      eq Literal.isFalse() = false;
293      eq BooleanLiteral.isFalse() = !constant().booleanValue();
294      eq LogNotExpr.isFalse() = getOperand().isTrue();
295    
296      syn Expr Binary.left() = getLeftOperand();
297      syn Expr Binary.right() = getRightOperand();
298      syn TypeDecl Binary.binaryNumericPromotedType() {
299        TypeDecl leftType = left().type();
300        TypeDecl rightType = right().type();
301        if (leftType.isString()) {
302          return leftType;
303        }
304        if (rightType.isString()) {
305          return rightType;
306        }
307        if (leftType.isNumericType() && rightType.isNumericType()) {
308          return leftType.binaryNumericPromotion(rightType);
309        }
310        if (leftType.isBoolean() && rightType.isBoolean()) {
311          return leftType;
312        }
313        return unknownType();
314      }
315    
316      eq LogNotExpr.constant() = Constant.create(!getOperand().constant().booleanValue());
317      eq EQExpr.constant() = Constant.create(binaryNumericPromotedType().eqIsTrue(left(), right()));
318      eq NEExpr.constant() = Constant.create(!binaryNumericPromotedType().eqIsTrue(left(), right()));
319      eq LTExpr.constant() = Constant.create(binaryNumericPromotedType().ltIsTrue(left(), right()));
320      eq LEExpr.constant() = Constant.create(binaryNumericPromotedType().leIsTrue(left(), right()));
321      eq GTExpr.constant() = Constant.create(!binaryNumericPromotedType().leIsTrue(left(), right()));
322      eq GEExpr.constant() = Constant.create(!binaryNumericPromotedType().ltIsTrue(left(), right()));
323      eq AndLogicalExpr.constant() = Constant.create(left().constant().booleanValue() && right().constant().booleanValue());
324      eq OrLogicalExpr.constant() = Constant.create(left().constant().booleanValue() || right().constant().booleanValue());
325    
326      syn boolean TypeDecl.eqIsTrue(Expr left, Expr right) {
327        System.err.println("Evaluation eqIsTrue for unknown type: " + getClass().getName());
328        return false;
329      }
330      eq IntegralType.eqIsTrue(Expr left, Expr right) = left.constant().intValue() == right.constant().intValue();
331      eq LongType.eqIsTrue(Expr left, Expr right) = left.constant().longValue() == right.constant().longValue();
332      eq FloatType.eqIsTrue(Expr left, Expr right) = left.constant().floatValue() == right.constant().floatValue();
333      eq DoubleType.eqIsTrue(Expr left, Expr right) = left.constant().doubleValue() == right.constant().doubleValue();
334      eq BooleanType.eqIsTrue(Expr left, Expr right) = left.isTrue() && right.isTrue() || left.isFalse() && right.isFalse();
335      eq ClassDecl.eqIsTrue(Expr left, Expr right) = isString() && left.constant().stringValue().equals(right.constant().stringValue());
336    
337      syn boolean TypeDecl.ltIsTrue(Expr left, Expr right) = false;
338      eq IntegralType.ltIsTrue(Expr left, Expr right) = left.constant().intValue() < right.constant().intValue();
339      eq LongType.ltIsTrue(Expr left, Expr right) = left.constant().longValue() < right.constant().longValue();
340      eq FloatType.ltIsTrue(Expr left, Expr right) = left.constant().floatValue() < right.constant().floatValue();
341      eq DoubleType.ltIsTrue(Expr left, Expr right) = left.constant().doubleValue() < right.constant().doubleValue();
342    
343      syn boolean TypeDecl.leIsTrue(Expr left, Expr right) = false;
344      eq IntegralType.leIsTrue(Expr left, Expr right) = left.constant().intValue() <= right.constant().intValue();
345      eq LongType.leIsTrue(Expr left, Expr right) = left.constant().longValue() <= right.constant().longValue();
346      eq FloatType.leIsTrue(Expr left, Expr right) = left.constant().floatValue() <= right.constant().floatValue();
347      eq DoubleType.leIsTrue(Expr left, Expr right) = left.constant().doubleValue() <= right.constant().doubleValue();
348    }
349