001    /*
002     * The JastAdd Extensible Java Compiler (http://jastadd.org) is covered
003     * by the modified BSD License. You should have received a copy of the
004     * modified BSD license with this compiler.
005     * 
006     * Copyright (c) 2005-2008, Torbjorn Ekman
007     *               2011       Jesper Öqvist <jesper.oqvist@cs.lth.se>
008     * All rights reserved.
009     */
010    
011    aspect ConstantExpression {
012      class Constant {
013        static class ConstantInt extends Constant {
014          private int value;
015          public ConstantInt(int i) { this.value = i; }
016          int intValue() { return value; }
017          long longValue() { return value; }
018          float floatValue() { return value; }
019          double doubleValue() { return value; }
020          String stringValue() { return new Integer(value).toString(); }
021        }
022        static class ConstantLong extends Constant {
023          private long value;
024          public ConstantLong(long l) { this.value = l; }
025          int intValue() { return (int)value; }
026          long longValue() { return value; }
027          float floatValue() { return value; }
028          double doubleValue() { return value; }
029          String stringValue() { return new Long(value).toString(); }
030        }
031        static class ConstantFloat extends Constant {
032          private float value;
033          public ConstantFloat(float f) { this.value = f; }
034          int intValue() { return (int)value; }
035          long longValue() { return (long)value; }
036          float floatValue() { return value; }
037          double doubleValue() { return value; }
038          String stringValue() { return new Float(value).toString(); }
039        }
040        static class ConstantDouble extends Constant {
041          private double value;
042          public ConstantDouble(double d) { this.value = d; }
043          int intValue() { return (int)value; }
044          long longValue() { return (long)value; }
045          float floatValue() { return (float)value; }
046          double doubleValue() { return value; }
047          String stringValue() { return new Double(value).toString(); }
048        }
049        static class ConstantChar extends Constant {
050          private char value;
051          public ConstantChar(char c) { this.value = c; }
052          int intValue() { return value; }
053          long longValue() { return value; }
054          float floatValue() { return value; }
055          double doubleValue() { return value; }
056          String stringValue() { return new Character(value).toString(); }
057        }
058        static class ConstantBoolean extends Constant {
059          private boolean value;
060          public ConstantBoolean(boolean b) { this.value = b; }
061          boolean booleanValue() { return value; }
062          String stringValue() { return new Boolean(value).toString(); }
063        }
064        static class ConstantString extends Constant {
065          private String value;
066          public ConstantString(String s) { this.value = s; }
067          String stringValue() { return value; }
068        }
069    
070        int intValue() { throw new UnsupportedOperationException(); }
071        long longValue() { throw new UnsupportedOperationException(); }
072        float floatValue() { throw new UnsupportedOperationException(); }
073        double doubleValue() { throw new UnsupportedOperationException(); }
074        boolean booleanValue() { throw new UnsupportedOperationException(getClass().getName()); }
075        String stringValue() { throw new UnsupportedOperationException(); }
076          
077        protected Constant() {
078        }
079        
080        public boolean error = false;
081    
082        static Constant create(int i) { return new ConstantInt(i); }
083        static Constant create(long l) { return new ConstantLong(l); }
084        static Constant create(float f) { return new ConstantFloat(f); }
085        static Constant create(double d) { return new ConstantDouble(d); }
086        static Constant create(boolean b) { return new ConstantBoolean(b); }
087        static Constant create(char c) { return new ConstantChar(c); }
088        static Constant create(String s) { return new ConstantString(s); }
089      }
090    
091      syn Constant Expr.constant() {
092        throw new UnsupportedOperationException("ConstantExpression operation constant" +
093          " not supported for type " + getClass().getName()); 
094      }
095      // enable caching for Literal constants
096      syn lazy Constant Literal.constant() {
097        throw new UnsupportedOperationException("ConstantExpression operation constant" +
098          " not supported for type " + getClass().getName()); 
099      }
100    
101      eq VarAccess.constant() = type().cast(decl().getInit().constant());
102      eq AbstractDot.constant() = lastAccess().constant();
103      eq CastExpr.constant() = type().cast(getExpr().constant());
104      eq ParExpr.constant() = getExpr().constant();
105    
106      eq PlusExpr.constant() = type().plus(getOperand().constant());
107      eq MinusExpr.constant() = type().minus(getOperand().constant());
108      eq BitNotExpr.constant() = type().bitNot(getOperand().constant());
109      
110      eq MulExpr.constant() = type().mul(getLeftOperand().constant(), getRightOperand().constant());
111      eq DivExpr.constant() = type().div(getLeftOperand().constant(), getRightOperand().constant());
112      eq ModExpr.constant() = type().mod(getLeftOperand().constant(), getRightOperand().constant());
113    
114      eq AddExpr.constant() = type().add(getLeftOperand().constant(), getRightOperand().constant());
115      eq SubExpr.constant() = type().sub(getLeftOperand().constant(), getRightOperand().constant());
116      
117      eq LShiftExpr.constant() = type().lshift(getLeftOperand().constant(), getRightOperand().constant());
118      eq RShiftExpr.constant() = type().rshift(getLeftOperand().constant(), getRightOperand().constant());
119      eq URShiftExpr.constant() = type().urshift(getLeftOperand().constant(), getRightOperand().constant());
120    
121      eq AndBitwiseExpr.constant() = type().andBitwise(getLeftOperand().constant(), getRightOperand().constant());
122      eq XorBitwiseExpr.constant() = type().xorBitwise(getLeftOperand().constant(), getRightOperand().constant());
123      eq OrBitwiseExpr.constant() = type().orBitwise(getLeftOperand().constant(), getRightOperand().constant());
124    
125      syn lazy Constant ConditionalExpr.constant() = type().questionColon(getCondition().constant(), getTrueExpr().constant(),getFalseExpr().constant());
126      
127      /*syn lazy boolean FloatingPointLiteral.isZero() {
128        String s = getLITERAL();
129        for(int i = 0; i < s.length(); i++) {
130          char c = s.charAt(i);
131          if(c == 'E'  || c == 'e')
132            break;
133          if(Character.isDigit(c) && c != '0') {
134            return false;
135          }
136        }
137        return true;
138      }
139      syn lazy boolean DoubleLiteral.isZero() {
140        String s = getLITERAL();
141        for(int i = 0; i < s.length(); i++) {
142          char c = s.charAt(i);
143          if(c == 'E'  || c == 'e')
144            break;
145          if(Character.isDigit(c) && c != '0') {
146            return false;
147          }
148        }
149        return true;
150      }*/
151      
152      syn boolean Expr.isPositive() = false;
153      eq IntegerLiteral.isPositive() = !getLITERAL().startsWith("-");
154      eq LongLiteral.isPositive() = !getLITERAL().startsWith("-");
155    
156      eq BooleanLiteral.constant() = Constant.create(Boolean.valueOf(getLITERAL()).booleanValue());
157      eq CharacterLiteral.constant() = Constant.create(getLITERAL().charAt(0));
158      eq StringLiteral.constant() = Constant.create(getLITERAL());
159      
160      syn Constant TypeDecl.cast(Constant c) {
161        throw new UnsupportedOperationException("ConstantExpression operation cast" +
162          " not supported for type " + getClass().getName()); 
163      }
164      eq IntegralType.cast(Constant c)= Constant.create(c.intValue());
165      eq ShortType.cast(Constant c) = Constant.create((short)c.intValue()); 
166      eq CharType.cast(Constant c) = Constant.create((char)c.intValue()); 
167      eq ByteType.cast(Constant c) = Constant.create((byte)c.intValue()); 
168      eq LongType.cast(Constant c) = Constant.create(c.longValue());
169      eq FloatType.cast(Constant c) = Constant.create(c.floatValue());
170      eq DoubleType.cast(Constant c) = Constant.create(c.doubleValue());
171      eq BooleanType.cast(Constant c) = Constant.create(c.booleanValue());
172      eq ClassDecl.cast(Constant c) = Constant.create(c.stringValue());
173    
174      syn Constant TypeDecl.plus(Constant c) {
175        throw new UnsupportedOperationException("ConstantExpression operation plus" +
176          " not supported for type " + getClass().getName()); 
177      }
178      eq IntegralType.plus(Constant c) = c;
179      eq LongType.plus(Constant c) = c;
180      eq FloatType.plus(Constant c) = c;
181      eq DoubleType.plus(Constant c) = c;
182      
183      syn Constant TypeDecl.minus(Constant c) {
184        throw new UnsupportedOperationException("ConstantExpression operation minus" +
185          " not supported for type " + getClass().getName()); 
186      }
187      eq IntegralType.minus(Constant c) = Constant.create(-c.intValue());
188      eq LongType.minus(Constant c) = Constant.create(-c.longValue());
189      eq FloatType.minus(Constant c) = Constant.create(-c.floatValue());
190      eq DoubleType.minus(Constant c) = Constant.create(-c.doubleValue());
191      
192      syn Constant TypeDecl.bitNot(Constant c) {
193        throw new UnsupportedOperationException("ConstantExpression operation bitNot" +
194          " not supported for type " + getClass().getName()); 
195      }
196      eq IntegralType.bitNot(Constant c) = Constant.create(~c.intValue());
197      eq LongType.bitNot(Constant c) = Constant.create(~c.longValue());
198      
199      syn Constant TypeDecl.mul(Constant c1, Constant c2) {
200        throw new UnsupportedOperationException("ConstantExpression operation mul" +
201          " not supported for type " + getClass().getName()); 
202      }
203      eq IntegralType.mul(Constant c1, Constant c2) = Constant.create(c1.intValue() * c2.intValue());
204      eq LongType.mul(Constant c1, Constant c2) = Constant.create(c1.longValue() * c2.longValue());
205      eq FloatType.mul(Constant c1, Constant c2) = Constant.create(c1.floatValue() * c2.floatValue());
206      eq DoubleType.mul(Constant c1, Constant c2) = Constant.create(c1.doubleValue() * c2.doubleValue());
207      
208      syn Constant TypeDecl.div(Constant c1, Constant c2) {
209        throw new UnsupportedOperationException("ConstantExpression operation div" +
210          " not supported for type " + getClass().getName()); 
211      }
212      eq IntegralType.div(Constant c1, Constant c2) = Constant.create(c1.intValue() / c2.intValue());
213      eq LongType.div(Constant c1, Constant c2) = Constant.create(c1.longValue() / c2.longValue());
214      eq FloatType.div(Constant c1, Constant c2) = Constant.create(c1.floatValue() / c2.floatValue());
215      eq DoubleType.div(Constant c1, Constant c2) = Constant.create(c1.doubleValue() / c2.doubleValue());
216      
217      syn Constant TypeDecl.mod(Constant c1, Constant c2) {
218        throw new UnsupportedOperationException("ConstantExpression operation mod" +
219          " not supported for type " + getClass().getName()); 
220      }
221      eq IntegralType.mod(Constant c1, Constant c2) = Constant.create(c1.intValue() % c2.intValue());
222      eq LongType.mod(Constant c1, Constant c2) = Constant.create(c1.longValue() % c2.longValue());
223      eq FloatType.mod(Constant c1, Constant c2) = Constant.create(c1.floatValue() % c2.floatValue());
224      eq DoubleType.mod(Constant c1, Constant c2) = Constant.create(c1.doubleValue() % c2.doubleValue());
225          
226      syn Constant TypeDecl.add(Constant c1, Constant c2) {
227        throw new UnsupportedOperationException("ConstantExpression operation add" +
228          " not supported for type " + getClass().getName()); 
229      }
230      eq IntegralType.add(Constant c1, Constant c2) = Constant.create(c1.intValue() + c2.intValue());
231      eq LongType.add(Constant c1, Constant c2) = Constant.create(c1.longValue() + c2.longValue());
232      eq FloatType.add(Constant c1, Constant c2) = Constant.create(c1.floatValue() + c2.floatValue());
233      eq DoubleType.add(Constant c1, Constant c2) = Constant.create(c1.doubleValue() + c2.doubleValue());
234      eq ClassDecl.add(Constant c1, Constant c2) = Constant.create(c1.stringValue() + c2.stringValue());
235    
236      syn Constant TypeDecl.sub(Constant c1, Constant c2) {
237        throw new UnsupportedOperationException("ConstantExpression operation sub" +
238          " not supported for type " + getClass().getName()); 
239      }
240      eq IntegralType.sub(Constant c1, Constant c2) = Constant.create(c1.intValue() - c2.intValue());
241      eq LongType.sub(Constant c1, Constant c2) = Constant.create(c1.longValue() - c2.longValue());
242      eq FloatType.sub(Constant c1, Constant c2) = Constant.create(c1.floatValue() - c2.floatValue());
243      eq DoubleType.sub(Constant c1, Constant c2) = Constant.create(c1.doubleValue() - c2.doubleValue());
244      
245      syn Constant TypeDecl.lshift(Constant c1, Constant c2) {
246        throw new UnsupportedOperationException("ConstantExpression operation lshift" +
247          " not supported for type " + getClass().getName()); 
248      }
249      eq IntegralType.lshift(Constant c1, Constant c2) = Constant.create(c1.intValue() << c2.intValue());
250      eq LongType.lshift(Constant c1, Constant c2) = Constant.create(c1.longValue() << c2.longValue());
251    
252      syn Constant TypeDecl.rshift(Constant c1, Constant c2) {
253        throw new UnsupportedOperationException("ConstantExpression operation rshift" +
254          " not supported for type " + getClass().getName()); 
255      }
256      eq IntegralType.rshift(Constant c1, Constant c2) = Constant.create(c1.intValue() >> c2.intValue());
257      eq LongType.rshift(Constant c1, Constant c2) = Constant.create(c1.longValue() >> c2.longValue());
258      
259      syn Constant TypeDecl.urshift(Constant c1, Constant c2) {
260        throw new UnsupportedOperationException("ConstantExpression operation urshift" +
261          " not supported for type " + getClass().getName()); 
262      }
263      eq IntegralType.urshift(Constant c1, Constant c2) = Constant.create(c1.intValue() >>> c2.intValue());
264      eq LongType.urshift(Constant c1, Constant c2) = Constant.create(c1.longValue() >>> c2.longValue());
265      
266      syn Constant TypeDecl.andBitwise(Constant c1, Constant c2) {
267        throw new UnsupportedOperationException("ConstantExpression operation andBitwise" +
268          " not supported for type " + getClass().getName()); 
269      }
270      eq IntegralType.andBitwise(Constant c1, Constant c2) = Constant.create(c1.intValue() & c2.intValue());
271      eq LongType.andBitwise(Constant c1, Constant c2) = Constant.create(c1.longValue() & c2.longValue());
272      eq BooleanType.andBitwise(Constant c1, Constant c2) = Constant.create(c1.booleanValue() & c2.booleanValue());
273    
274      syn Constant TypeDecl.xorBitwise(Constant c1, Constant c2) {
275        throw new UnsupportedOperationException("ConstantExpression operation xorBitwise" +
276          " not supported for type " + getClass().getName()); 
277      }
278      eq IntegralType.xorBitwise(Constant c1, Constant c2) = Constant.create(c1.intValue() ^ c2.intValue());
279      eq LongType.xorBitwise(Constant c1, Constant c2) = Constant.create(c1.longValue() ^ c2.longValue());
280      eq BooleanType.xorBitwise(Constant c1, Constant c2) = Constant.create(c1.booleanValue() ^ c2.booleanValue());
281      
282      syn Constant TypeDecl.orBitwise(Constant c1, Constant c2) {
283        throw new UnsupportedOperationException("ConstantExpression operation orBitwise" +
284          " not supported for type " + getClass().getName()); 
285      }
286      eq IntegralType.orBitwise(Constant c1, Constant c2) = Constant.create(c1.intValue() | c2.intValue());
287      eq LongType.orBitwise(Constant c1, Constant c2) = Constant.create(c1.longValue() | c2.longValue());
288      eq BooleanType.orBitwise(Constant c1, Constant c2) = Constant.create(c1.booleanValue() | c2.booleanValue());
289    
290      syn Constant TypeDecl.questionColon(Constant cond, Constant c1, Constant c2) {
291        throw new UnsupportedOperationException("ConstantExpression operation questionColon" +
292          " not supported for type " + getClass().getName()); 
293      }
294      eq IntegralType.questionColon(Constant cond, Constant c1, Constant c2) = Constant.create(cond.booleanValue() ? c1.intValue() : c2.intValue());
295      eq LongType.questionColon(Constant cond, Constant c1, Constant c2) = Constant.create(cond.booleanValue() ? c1.longValue() : c2.longValue());
296      eq FloatType.questionColon(Constant cond, Constant c1, Constant c2) = Constant.create(cond.booleanValue() ? c1.floatValue() : c2.floatValue());
297      eq DoubleType.questionColon(Constant cond, Constant c1, Constant c2) = Constant.create(cond.booleanValue() ? c1.doubleValue() : c2.doubleValue());
298      eq BooleanType.questionColon(Constant cond, Constant c1, Constant c2) = Constant.create(cond.booleanValue() ? c1.booleanValue() : c2.booleanValue());
299      eq ClassDecl.questionColon(Constant cond, Constant c1, Constant c2) = Constant.create(cond.booleanValue() ? c1.stringValue() : c2.stringValue());
300     
301      /* 
302       * representableIn(T) is true if and only if the the expression is a 
303       * compile-time constant of type byte, char, short or int, and the value  
304       * of the expression can be represented (by an expression) in the type T
305       * where T must be byte, char or short.
306       */
307       
308      syn boolean Expr.representableIn(TypeDecl t) {   
309       if (!type().isByte() && !type().isChar() && !type().isShort() && !type().isInt()) {
310               return false;
311       }
312       if (t.isByte())
313               return constant().intValue() >= Byte.MIN_VALUE && constant().intValue() <= Byte.MAX_VALUE;
314       if (t.isChar())
315               return constant().intValue() >= Character.MIN_VALUE && constant().intValue() <= Character.MAX_VALUE;
316       if (t.isShort())
317               return constant().intValue() >= Short.MIN_VALUE && constant().intValue() <= Short.MAX_VALUE;
318        if(t.isInt()) 
319          return constant().intValue() >= Integer.MIN_VALUE && constant().intValue() <= Integer.MAX_VALUE;
320         return false;
321      } 
322      
323      eq ArrayInit.representableIn(TypeDecl t) {
324        for(int i = 0; i < getNumInit(); i++)
325          if(!getInit(i).representableIn(t))
326            return false;
327        return true;
328      }
329    
330      // isConstant()
331      
332      syn boolean MemberDecl.isConstant() = false;
333      eq FieldDeclaration.isConstant() = isFinal() && hasInit() && getInit().isConstant() && (type() instanceof PrimitiveType || type().isString());
334    
335    
336      syn boolean Expr.isConstant() = false;
337      eq Literal.isConstant() = true;
338      eq NullLiteral.isConstant() = false;
339      eq CastExpr.isConstant() = getExpr().isConstant() &&
340        (getTypeAccess().type().isPrimitive() || getTypeAccess().type().isString());
341      eq PlusExpr.isConstant() = getOperand().isConstant();
342      eq MinusExpr.isConstant() = getOperand().isConstant();
343      eq BitNotExpr.isConstant() = getOperand().isConstant();
344      eq LogNotExpr.isConstant() = getOperand().isConstant();
345      syn lazy boolean Binary.isConstant() circular [false] = getLeftOperand().isConstant() && getRightOperand().isConstant();
346      eq InstanceOfExpr.isConstant() = false;
347      syn lazy boolean ConditionalExpr.isConstant() = getCondition().isConstant() && getTrueExpr().isConstant() && getFalseExpr().isConstant();
348      eq ParExpr.isConstant() = getExpr().isConstant();
349      eq AbstractDot.isConstant() = lastAccess().isConstant();
350    
351      eq DivExpr.isConstant() = getLeftOperand().isConstant() && getRightOperand().isConstant() && !(getRightOperand().type().isInt() && getRightOperand().constant().intValue() == 0);
352      eq ModExpr.isConstant() = getLeftOperand().isConstant() && getRightOperand().isConstant() && !(getRightOperand().type().isInt() && getRightOperand().constant().intValue() == 0);
353      
354      syn lazy boolean VarAccess.isConstant() circular [false] {
355        Variable v = decl();
356        if(v instanceof FieldDeclaration) {
357          FieldDeclaration f = (FieldDeclaration)v;
358          return f.isConstant() && (!isQualified() || (isQualified() && qualifier().isTypeAccess()));
359        }
360        boolean result = v.isFinal() && v.hasInit() && v.getInit().isConstant() && (v.type().isPrimitive() || v.type().isString());
361        return result && (!isQualified() || (isQualified() && qualifier().isTypeAccess()));
362      }
363    
364      // BooleanType is used to discard UnknownType which also responds true for isBoolean()
365      syn boolean Expr.isTrue() = isConstant() && type() instanceof BooleanType && constant().booleanValue();
366      syn boolean Expr.isFalse() = isConstant() && type() instanceof BooleanType && !constant().booleanValue();
367    
368      syn Expr Binary.left() = getLeftOperand();
369      syn Expr Binary.right() = getRightOperand();
370      syn TypeDecl Binary.binaryNumericPromotedType() {
371        TypeDecl leftType = left().type();
372        TypeDecl rightType = right().type();
373        if(leftType.isString())
374          return leftType;
375        if(rightType.isString())
376          return rightType;
377        if(leftType.isNumericType() && rightType.isNumericType())
378          return leftType.binaryNumericPromotion(rightType);
379        if(leftType.isBoolean() && rightType.isBoolean())
380          return leftType;
381        return unknownType();
382      }
383    
384      eq LogNotExpr.constant() = Constant.create(!getOperand().constant().booleanValue());
385      eq EQExpr.constant() = Constant.create(binaryNumericPromotedType().eqIsTrue(left(), right()));
386      eq NEExpr.constant() = Constant.create(!binaryNumericPromotedType().eqIsTrue(left(), right()));
387      eq LTExpr.constant() = Constant.create(binaryNumericPromotedType().ltIsTrue(left(), right()));
388      eq LEExpr.constant() = Constant.create(binaryNumericPromotedType().leIsTrue(left(), right()));
389      eq GTExpr.constant() = Constant.create(!binaryNumericPromotedType().leIsTrue(left(), right()));
390      eq GEExpr.constant() = Constant.create(!binaryNumericPromotedType().ltIsTrue(left(), right()));
391      eq AndLogicalExpr.constant() = Constant.create(left().constant().booleanValue() && right().constant().booleanValue());
392      eq OrLogicalExpr.constant() = Constant.create(left().constant().booleanValue() || right().constant().booleanValue());
393      
394      syn boolean TypeDecl.eqIsTrue(Expr left, Expr right) {
395        System.err.println("Evaluation eqIsTrue for unknown type: " + getClass().getName());
396        return false;
397      }
398      eq IntegralType.eqIsTrue(Expr left, Expr right) = left.constant().intValue() == right.constant().intValue();
399      eq LongType.eqIsTrue(Expr left, Expr right) = left.constant().longValue() == right.constant().longValue();
400      eq FloatType.eqIsTrue(Expr left, Expr right) = left.constant().floatValue() == right.constant().floatValue();
401      eq DoubleType.eqIsTrue(Expr left, Expr right) = left.constant().doubleValue() == right.constant().doubleValue();
402      eq BooleanType.eqIsTrue(Expr left, Expr right) = left.isTrue() && right.isTrue() || left.isFalse() && right.isFalse();
403      eq ClassDecl.eqIsTrue(Expr left, Expr right) = isString() && left.constant().stringValue().equals(right.constant().stringValue());
404      
405      syn boolean TypeDecl.ltIsTrue(Expr left, Expr right) = false;
406      eq IntegralType.ltIsTrue(Expr left, Expr right) = left.constant().intValue() < right.constant().intValue();
407      eq LongType.ltIsTrue(Expr left, Expr right) = left.constant().longValue() < right.constant().longValue();
408      eq FloatType.ltIsTrue(Expr left, Expr right) = left.constant().floatValue() < right.constant().floatValue();
409      eq DoubleType.ltIsTrue(Expr left, Expr right) = left.constant().doubleValue() < right.constant().doubleValue();
410    
411      syn boolean TypeDecl.leIsTrue(Expr left, Expr right) = false;
412      eq IntegralType.leIsTrue(Expr left, Expr right) = left.constant().intValue() <= right.constant().intValue();
413      eq LongType.leIsTrue(Expr left, Expr right) = left.constant().longValue() <= right.constant().longValue();
414      eq FloatType.leIsTrue(Expr left, Expr right) = left.constant().floatValue() <= right.constant().floatValue();
415      eq DoubleType.leIsTrue(Expr left, Expr right) = left.constant().doubleValue() <= right.constant().doubleValue();
416    }
417