ConstEvaluator.java revision 5bd34220e797da6446ba3f69aae9d62023171a9e
1/*
2 * Copyright 2016 Google Inc. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.google.turbine.binder;
18
19import static com.google.common.base.Preconditions.checkNotNull;
20import static com.google.common.base.Verify.verifyNotNull;
21
22import com.google.common.base.Joiner;
23import com.google.common.collect.ImmutableList;
24import com.google.common.collect.ImmutableMap;
25import com.google.turbine.binder.bound.SourceTypeBoundClass;
26import com.google.turbine.binder.bound.TypeBoundClass;
27import com.google.turbine.binder.bound.TypeBoundClass.AnnoInfo;
28import com.google.turbine.binder.bound.TypeBoundClass.FieldInfo;
29import com.google.turbine.binder.bound.TypeBoundClass.MethodInfo;
30import com.google.turbine.binder.env.CompoundEnv;
31import com.google.turbine.binder.env.Env;
32import com.google.turbine.binder.lookup.LookupKey;
33import com.google.turbine.binder.lookup.LookupResult;
34import com.google.turbine.binder.sym.ClassSymbol;
35import com.google.turbine.binder.sym.FieldSymbol;
36import com.google.turbine.model.Const;
37import com.google.turbine.model.TurbineConstantTypeKind;
38import com.google.turbine.model.TurbineFlag;
39import com.google.turbine.tree.Tree;
40import com.google.turbine.tree.Tree.ArrayInit;
41import com.google.turbine.tree.Tree.Binary;
42import com.google.turbine.tree.Tree.ClassLiteral;
43import com.google.turbine.tree.Tree.ClassTy;
44import com.google.turbine.tree.Tree.Conditional;
45import com.google.turbine.tree.Tree.ConstVarName;
46import com.google.turbine.tree.Tree.Expression;
47import com.google.turbine.tree.Tree.PrimTy;
48import com.google.turbine.tree.Tree.TypeCast;
49import com.google.turbine.tree.Tree.Unary;
50import com.google.turbine.type.Type;
51import java.util.LinkedHashMap;
52import java.util.Map;
53
54/** Constant expression evaluation. */
55public class ConstEvaluator {
56
57  /** The symbol of the enclosing class. */
58  private final ClassSymbol sym;
59
60  /** The bound node of the enclosing class. */
61  private final SourceTypeBoundClass owner;
62
63  /** The constant variable environment. */
64  private final Env<FieldSymbol, Const.Value> values;
65
66  /** The class environment. */
67  private final CompoundEnv<ClassSymbol, TypeBoundClass> env;
68
69  public ConstEvaluator(
70      ClassSymbol sym,
71      SourceTypeBoundClass owner,
72      Env<FieldSymbol, Const.Value> values,
73      CompoundEnv<ClassSymbol, TypeBoundClass> env) {
74
75    this.sym = sym;
76    this.owner = owner;
77    this.values = values;
78    this.env = env;
79  }
80
81  /** Evaluates the given expression's value. */
82  public Const eval(Tree t) {
83    switch (t.kind()) {
84      case LITERAL:
85        {
86          Const.Value a = (Const.Value) ((Tree.Literal) t).value();
87          if (a == null) {
88            return null;
89          }
90          switch (a.constantTypeKind()) {
91            case CHAR:
92              return new Const.CharValue(((com.google.turbine.model.Const.CharValue) a).value());
93            case INT:
94              return new Const.IntValue(((com.google.turbine.model.Const.IntValue) a).value());
95            case LONG:
96              return new Const.LongValue(((com.google.turbine.model.Const.LongValue) a).value());
97            case FLOAT:
98              return new Const.FloatValue(((com.google.turbine.model.Const.FloatValue) a).value());
99            case DOUBLE:
100              return new Const.DoubleValue(
101                  ((com.google.turbine.model.Const.DoubleValue) a).value());
102            case BOOLEAN:
103              return new Const.BooleanValue(
104                  ((com.google.turbine.model.Const.BooleanValue) a).value());
105            case STRING:
106              return new Const.StringValue(
107                  ((com.google.turbine.model.Const.StringValue) a).value());
108            case SHORT:
109            case BYTE:
110            case NULL:
111            default:
112              throw new AssertionError(a.constantTypeKind());
113          }
114        }
115      case VOID_TY:
116        throw new AssertionError(t.kind());
117      case CONST_VAR_NAME:
118        return evalConstVar((ConstVarName) t);
119      case CLASS_LITERAL:
120        return evalClassLiteral((ClassLiteral) t);
121      case BINARY:
122        return evalBinary((Binary) t);
123      case TYPE_CAST:
124        return evalCast((TypeCast) t);
125      case UNARY:
126        return evalUnary((Unary) t);
127      case CONDITIONAL:
128        return evalConditional((Conditional) t);
129      case ARRAY_INIT:
130        return evalArrayInit((ArrayInit) t);
131      case ANNO_EXPR:
132        return evalAnno(((Tree.AnnoExpr) t).value());
133      default:
134        throw new AssertionError(t.kind());
135    }
136  }
137
138  /** Evaluates a class literal. */
139  // TODO(cushon): consider distinguishing between constant field and annotation values,
140  // and only allowing class literals / enum constants in the latter
141  Const evalClassLiteral(ClassLiteral t) {
142    switch (t.type().kind()) {
143      case PRIM_TY:
144        return new Const.ClassValue(new Type.PrimTy(((PrimTy) t.type()).tykind()));
145      case VOID_TY:
146        return new Const.ClassValue(Type.VOID);
147      case CLASS_TY:
148        {
149          ClassTy classTy = (ClassTy) t.type();
150          ClassSymbol classSym = HierarchyBinder.resolveClass(env, owner.scope(), sym, classTy);
151          return new Const.ClassValue(Type.ClassTy.asNonParametricClassTy(classSym));
152        }
153      default:
154        throw new AssertionError(t.type().kind());
155    }
156  }
157
158  /** Evaluates a reference to another constant variable. */
159  Const evalConstVar(ConstVarName t) {
160    LookupResult result = owner.scope().lookup(new LookupKey(t.name()));
161    if (result != null) {
162      return resolve(result);
163    }
164    String simple = t.name().get(0);
165    FieldInfo info = lexicalField(env, sym, simple);
166    if (info != null) {
167      return values.get(info.sym());
168    }
169    // This resolves the top-level class symbol, and then doesn inherited member
170    // lookup on the rest of the names. The spec only allows the final name to be
171    // inherited and requires canonical form for the rest, so consider enforcing
172    // that.
173    result = owner.memberImports().lookup(simple);
174    if (result != null) {
175      return resolve(result);
176    }
177    throw new AssertionError(Joiner.on('.').join(t.name()));
178  }
179
180  private Const resolve(LookupResult result) {
181    ClassSymbol sym = (ClassSymbol) result.sym();
182    for (int i = 0; i < result.remaining().size() - 1; i++) {
183      sym = Resolve.resolve(env, sym, result.remaining().get(i));
184    }
185    String name = result.remaining().get(result.remaining().size() - 1);
186    FieldInfo field = inheritedField(env, sym, name);
187    if ((field.access() & TurbineFlag.ACC_ENUM) == TurbineFlag.ACC_ENUM) {
188      return new Const.EnumConstantValue(field.sym());
189    }
190    verifyNotNull(field, "%s", result);
191    return values.get(field.sym());
192  }
193
194  /** Search for constant variables in lexically enclosing scopes. */
195  private static FieldInfo lexicalField(
196      Env<ClassSymbol, TypeBoundClass> env, ClassSymbol sym, String name) {
197    while (sym != null) {
198      TypeBoundClass info = env.get(sym);
199      FieldInfo field = inheritedField(env, sym, name);
200      if (field != null) {
201        return field;
202      }
203      sym = info.owner();
204    }
205    return null;
206  }
207
208  private static FieldInfo inheritedField(
209      Env<ClassSymbol, TypeBoundClass> env, ClassSymbol sym, String name) {
210    while (sym != null) {
211      TypeBoundClass info = env.get(sym);
212      FieldInfo field = getField(info, name);
213      if (field != null) {
214        return field;
215      }
216      sym = info.superclass();
217    }
218    return null;
219  }
220
221  private static FieldInfo getField(TypeBoundClass info, String name) {
222    for (FieldInfo f : info.fields()) {
223      if (f.name().equals(name)) {
224        return f;
225      }
226    }
227    return null;
228  }
229
230  /** Casts the value to the given type. */
231  static Const cast(Type ty, Const value) {
232    checkNotNull(value);
233    switch (ty.tyKind()) {
234      case CLASS_TY:
235      case TY_VAR:
236        return value;
237      case PRIM_TY:
238        return coerce((Const.Value) value, ((Type.PrimTy) ty).primkind());
239      default:
240        throw new AssertionError(ty.tyKind());
241    }
242  }
243
244  private static Const.Value coerce(Const.Value value, TurbineConstantTypeKind kind) {
245    switch (kind) {
246      case BOOLEAN:
247        return value.asBoolean();
248      case STRING:
249        return value.asString();
250      case LONG:
251        return value.asLong();
252      case INT:
253        return value.asInteger();
254      case BYTE:
255        return value.asByte();
256      case CHAR:
257        return value.asChar();
258      case SHORT:
259        return value.asShort();
260      case DOUBLE:
261        return value.asDouble();
262      case FLOAT:
263        return value.asFloat();
264      default:
265        throw new AssertionError(kind);
266    }
267  }
268
269  private Const.Value evalValue(Expression tree) {
270    return (Const.Value) eval(tree);
271  }
272
273  private Const.Value evalConditional(Conditional t) {
274    return evalValue(t.cond()).asBoolean().value() ? evalValue(t.iftrue()) : evalValue(t.iffalse());
275  }
276
277  private Const.Value evalUnary(Unary t) {
278    Const.Value expr = evalValue(t.expr());
279    switch (t.op()) {
280      case NOT:
281        switch (expr.constantTypeKind()) {
282          case BOOLEAN:
283            return new Const.BooleanValue(!expr.asBoolean().value());
284          default:
285            throw new AssertionError(expr.constantTypeKind());
286        }
287      case BITWISE_COMP:
288        switch (expr.constantTypeKind()) {
289          case INT:
290            return new Const.IntValue(~expr.asInteger().value());
291          case LONG:
292            return new Const.LongValue(~expr.asLong().value());
293          case BYTE:
294            return new Const.ByteValue((byte) ~expr.asByte().value());
295          case SHORT:
296            return new Const.ShortValue((short) ~expr.asShort().value());
297          case CHAR:
298            return new Const.CharValue((char) ~expr.asChar().value());
299          default:
300            throw new AssertionError(expr.constantTypeKind());
301        }
302      case UNARY_PLUS:
303        switch (expr.constantTypeKind()) {
304          case INT:
305            return new Const.IntValue(+expr.asInteger().value());
306          case LONG:
307            return new Const.LongValue(+expr.asLong().value());
308          case BYTE:
309            return new Const.ByteValue((byte) +expr.asByte().value());
310          case SHORT:
311            return new Const.ShortValue((short) +expr.asShort().value());
312          case CHAR:
313            return new Const.CharValue((char) +expr.asChar().value());
314          case FLOAT:
315            return new Const.FloatValue(+expr.asFloat().value());
316          case DOUBLE:
317            return new Const.DoubleValue(+expr.asDouble().value());
318          default:
319            throw new AssertionError(expr.constantTypeKind());
320        }
321      case NEG:
322        switch (expr.constantTypeKind()) {
323          case INT:
324            return new Const.IntValue(-expr.asInteger().value());
325          case BYTE:
326            return new Const.ByteValue((byte) -expr.asByte().value());
327          case SHORT:
328            return new Const.ShortValue((short) -expr.asShort().value());
329          case CHAR:
330            return new Const.CharValue((char) -expr.asChar().value());
331          case LONG:
332            return new Const.LongValue(-expr.asLong().value());
333          case FLOAT:
334            return new Const.FloatValue(-expr.asFloat().value());
335          case DOUBLE:
336            return new Const.DoubleValue(-expr.asDouble().value());
337          default:
338            throw new AssertionError(expr.constantTypeKind());
339        }
340      default:
341        throw new AssertionError(t.op());
342    }
343  }
344
345  private Const.Value evalCast(TypeCast t) {
346    Const.Value expr = evalValue(t.expr());
347    switch (t.ty().kind()) {
348      case PRIM_TY:
349        return coerce(expr, ((Tree.PrimTy) t.ty()).tykind());
350      case CLASS_TY:
351        {
352          ClassTy classTy = (ClassTy) t.ty();
353          // TODO(cushon): check package?
354          if (!classTy.name().equals("String")) {
355            throw new AssertionError(classTy);
356          }
357          return expr.asString();
358        }
359      default:
360        throw new AssertionError(t.ty().kind());
361    }
362  }
363
364  static Const.Value add(Const.Value a, Const.Value b) {
365    if (a.constantTypeKind() == TurbineConstantTypeKind.STRING
366        || b.constantTypeKind() == TurbineConstantTypeKind.STRING) {
367      return new Const.StringValue(a.asString().value() + b.asString().value());
368    }
369    TurbineConstantTypeKind type = promoteBinary(a, b);
370    a = coerce(a, type);
371    b = coerce(b, type);
372    switch (type) {
373      case INT:
374        return new Const.IntValue(a.asInteger().value() + b.asInteger().value());
375      case LONG:
376        return new Const.LongValue(a.asLong().value() + b.asLong().value());
377      case FLOAT:
378        return new Const.FloatValue(a.asFloat().value() + b.asFloat().value());
379      case DOUBLE:
380        return new Const.DoubleValue(a.asDouble().value() + b.asDouble().value());
381      default:
382        throw new AssertionError(type);
383    }
384  }
385
386  static Const.Value subtract(Const.Value a, Const.Value b) {
387    TurbineConstantTypeKind type = promoteBinary(a, b);
388    a = coerce(a, type);
389    b = coerce(b, type);
390    switch (type) {
391      case INT:
392        return new Const.IntValue(a.asInteger().value() - b.asInteger().value());
393      case LONG:
394        return new Const.LongValue(a.asLong().value() - b.asLong().value());
395      case FLOAT:
396        return new Const.FloatValue(a.asFloat().value() - b.asFloat().value());
397      case DOUBLE:
398        return new Const.DoubleValue(a.asDouble().value() - b.asDouble().value());
399      default:
400        throw new AssertionError(type);
401    }
402  }
403
404  static Const.Value mult(Const.Value a, Const.Value b) {
405    TurbineConstantTypeKind type = promoteBinary(a, b);
406    a = coerce(a, type);
407    b = coerce(b, type);
408    switch (type) {
409      case INT:
410        return new Const.IntValue(a.asInteger().value() * b.asInteger().value());
411      case LONG:
412        return new Const.LongValue(a.asLong().value() * b.asLong().value());
413      case FLOAT:
414        return new Const.FloatValue(a.asFloat().value() * b.asFloat().value());
415      case DOUBLE:
416        return new Const.DoubleValue(a.asDouble().value() * b.asDouble().value());
417      default:
418        throw new AssertionError(type);
419    }
420  }
421
422  static Const.Value divide(Const.Value a, Const.Value b) {
423    TurbineConstantTypeKind type = promoteBinary(a, b);
424    a = coerce(a, type);
425    b = coerce(b, type);
426    switch (type) {
427      case INT:
428        return new Const.IntValue(a.asInteger().value() / b.asInteger().value());
429      case LONG:
430        return new Const.LongValue(a.asLong().value() / b.asLong().value());
431      case FLOAT:
432        return new Const.FloatValue(a.asFloat().value() / b.asFloat().value());
433      case DOUBLE:
434        return new Const.DoubleValue(a.asDouble().value() / b.asDouble().value());
435      default:
436        throw new AssertionError(type);
437    }
438  }
439
440  static Const.Value mod(Const.Value a, Const.Value b) {
441    TurbineConstantTypeKind type = promoteBinary(a, b);
442    a = coerce(a, type);
443    b = coerce(b, type);
444    switch (type) {
445      case INT:
446        return new Const.IntValue(a.asInteger().value() % b.asInteger().value());
447      case LONG:
448        return new Const.LongValue(a.asLong().value() % b.asLong().value());
449      case FLOAT:
450        return new Const.FloatValue(a.asFloat().value() % b.asFloat().value());
451      case DOUBLE:
452        return new Const.DoubleValue(a.asDouble().value() % b.asDouble().value());
453      default:
454        throw new AssertionError(type);
455    }
456  }
457
458  static final int INT_SHIFT_MASK = 0b11111;
459
460  static final int LONG_SHIFT_MASK = 0b111111;
461
462  static Const.Value shiftLeft(Const.Value a, Const.Value b) {
463    a = promoteUnary(a);
464    b = promoteUnary(b);
465    switch (a.constantTypeKind()) {
466      case INT:
467        return new Const.IntValue(
468            a.asInteger().value() << (b.asInteger().value() & INT_SHIFT_MASK));
469      case LONG:
470        return new Const.LongValue(a.asLong().value() << (b.asInteger().value() & LONG_SHIFT_MASK));
471      default:
472        throw new AssertionError(a.constantTypeKind());
473    }
474  }
475
476  static Const.Value shiftRight(Const.Value a, Const.Value b) {
477    a = promoteUnary(a);
478    b = promoteUnary(b);
479    switch (a.constantTypeKind()) {
480      case INT:
481        return new Const.IntValue(
482            a.asInteger().value() >> (b.asInteger().value() & INT_SHIFT_MASK));
483      case LONG:
484        return new Const.LongValue(a.asLong().value() >> (b.asInteger().value() & LONG_SHIFT_MASK));
485      default:
486        throw new AssertionError(a.constantTypeKind());
487    }
488  }
489
490  static Const.Value unsignedShiftRight(Const.Value a, Const.Value b) {
491    a = promoteUnary(a);
492    b = promoteUnary(b);
493    switch (a.constantTypeKind()) {
494      case INT:
495        return new Const.IntValue(
496            a.asInteger().value() >>> (b.asInteger().value() & INT_SHIFT_MASK));
497      case LONG:
498        return new Const.LongValue(
499            a.asLong().value() >>> (b.asInteger().value() & LONG_SHIFT_MASK));
500      default:
501        throw new AssertionError(a.constantTypeKind());
502    }
503  }
504
505  static Const.Value lessThan(Const.Value a, Const.Value b) {
506    TurbineConstantTypeKind type = promoteBinary(a, b);
507    a = coerce(a, type);
508    b = coerce(b, type);
509    switch (type) {
510      case INT:
511        return new Const.BooleanValue(a.asInteger().value() < b.asInteger().value());
512      case LONG:
513        return new Const.BooleanValue(a.asLong().value() < b.asLong().value());
514      case FLOAT:
515        return new Const.BooleanValue(a.asFloat().value() < b.asFloat().value());
516      case DOUBLE:
517        return new Const.BooleanValue(a.asDouble().value() < b.asDouble().value());
518      default:
519        throw new AssertionError(type);
520    }
521  }
522
523  static Const.Value lessThanEqual(Const.Value a, Const.Value b) {
524    TurbineConstantTypeKind type = promoteBinary(a, b);
525    a = coerce(a, type);
526    b = coerce(b, type);
527    switch (type) {
528      case INT:
529        return new Const.BooleanValue(a.asInteger().value() <= b.asInteger().value());
530      case LONG:
531        return new Const.BooleanValue(a.asLong().value() <= b.asLong().value());
532      case FLOAT:
533        return new Const.BooleanValue(a.asFloat().value() <= b.asFloat().value());
534      case DOUBLE:
535        return new Const.BooleanValue(a.asDouble().value() <= b.asDouble().value());
536      default:
537        throw new AssertionError(type);
538    }
539  }
540
541  static Const.Value greaterThan(Const.Value a, Const.Value b) {
542    TurbineConstantTypeKind type = promoteBinary(a, b);
543    a = coerce(a, type);
544    b = coerce(b, type);
545    switch (type) {
546      case INT:
547        return new Const.BooleanValue(a.asInteger().value() > b.asInteger().value());
548      case LONG:
549        return new Const.BooleanValue(a.asLong().value() > b.asLong().value());
550      case FLOAT:
551        return new Const.BooleanValue(a.asFloat().value() > b.asFloat().value());
552      case DOUBLE:
553        return new Const.BooleanValue(a.asDouble().value() > b.asDouble().value());
554      default:
555        throw new AssertionError(type);
556    }
557  }
558
559  static Const.Value greaterThanEqual(Const.Value a, Const.Value b) {
560    TurbineConstantTypeKind type = promoteBinary(a, b);
561    a = coerce(a, type);
562    b = coerce(b, type);
563    switch (type) {
564      case INT:
565        return new Const.BooleanValue(a.asInteger().value() >= b.asInteger().value());
566      case LONG:
567        return new Const.BooleanValue(a.asLong().value() >= b.asLong().value());
568      case FLOAT:
569        return new Const.BooleanValue(a.asFloat().value() >= b.asFloat().value());
570      case DOUBLE:
571        return new Const.BooleanValue(a.asDouble().value() >= b.asDouble().value());
572      default:
573        throw new AssertionError(type);
574    }
575  }
576
577  static Const.Value equal(Const.Value a, Const.Value b) {
578    switch (a.constantTypeKind()) {
579      case STRING:
580        return new Const.BooleanValue(a.asString().value().equals(b.asString().value()));
581      case BOOLEAN:
582        return new Const.BooleanValue(a.asBoolean().value() == b.asBoolean().value());
583      default:
584        break;
585    }
586    TurbineConstantTypeKind type = promoteBinary(a, b);
587    a = coerce(a, type);
588    b = coerce(b, type);
589    switch (type) {
590      case INT:
591        return new Const.BooleanValue(a.asInteger().value() == b.asInteger().value());
592      case LONG:
593        return new Const.BooleanValue(a.asLong().value() == b.asLong().value());
594      case FLOAT:
595        return new Const.BooleanValue(a.asFloat().value() == b.asFloat().value());
596      case DOUBLE:
597        return new Const.BooleanValue(a.asDouble().value() == b.asDouble().value());
598      default:
599        throw new AssertionError(type);
600    }
601  }
602
603  static Const.Value notEqual(Const.Value a, Const.Value b) {
604    switch (a.constantTypeKind()) {
605      case STRING:
606        return new Const.BooleanValue(!a.asString().value().equals(b.asString().value()));
607      case BOOLEAN:
608        return new Const.BooleanValue(a.asBoolean().value() != b.asBoolean().value());
609      default:
610        break;
611    }
612    TurbineConstantTypeKind type = promoteBinary(a, b);
613    a = coerce(a, type);
614    b = coerce(b, type);
615    switch (type) {
616      case INT:
617        return new Const.BooleanValue(a.asInteger().value() != b.asInteger().value());
618      case LONG:
619        return new Const.BooleanValue(a.asLong().value() != b.asLong().value());
620      case FLOAT:
621        return new Const.BooleanValue(a.asFloat().value() != b.asFloat().value());
622      case DOUBLE:
623        return new Const.BooleanValue(a.asDouble().value() != b.asDouble().value());
624      default:
625        throw new AssertionError(type);
626    }
627  }
628
629  static Const.Value bitwiseAnd(Const.Value a, Const.Value b) {
630    switch (a.constantTypeKind()) {
631      case BOOLEAN:
632        return new Const.BooleanValue(a.asBoolean().value() & b.asBoolean().value());
633      default:
634        break;
635    }
636    TurbineConstantTypeKind type = promoteBinary(a, b);
637    a = coerce(a, type);
638    b = coerce(b, type);
639    switch (type) {
640      case INT:
641        return new Const.IntValue(a.asInteger().value() & b.asInteger().value());
642      case LONG:
643        return new Const.LongValue(a.asLong().value() & b.asLong().value());
644      default:
645        throw new AssertionError(type);
646    }
647  }
648
649  static Const.Value bitwiseOr(Const.Value a, Const.Value b) {
650    switch (a.constantTypeKind()) {
651      case BOOLEAN:
652        return new Const.BooleanValue(a.asBoolean().value() | b.asBoolean().value());
653      default:
654        break;
655    }
656    TurbineConstantTypeKind type = promoteBinary(a, b);
657    a = coerce(a, type);
658    b = coerce(b, type);
659    switch (type) {
660      case INT:
661        return new Const.IntValue(a.asInteger().value() | b.asInteger().value());
662      case LONG:
663        return new Const.LongValue(a.asLong().value() | b.asLong().value());
664      default:
665        throw new AssertionError(type);
666    }
667  }
668
669  static Const.Value bitwiseXor(Const.Value a, Const.Value b) {
670    switch (a.constantTypeKind()) {
671      case BOOLEAN:
672        return new Const.BooleanValue(a.asBoolean().value() ^ b.asBoolean().value());
673      default:
674        break;
675    }
676    TurbineConstantTypeKind type = promoteBinary(a, b);
677    a = coerce(a, type);
678    b = coerce(b, type);
679    switch (type) {
680      case INT:
681        return new Const.IntValue(a.asInteger().value() ^ b.asInteger().value());
682      case LONG:
683        return new Const.LongValue(a.asLong().value() ^ b.asLong().value());
684      default:
685        throw new AssertionError(type);
686    }
687  }
688
689  private Const.Value evalBinary(Binary t) {
690    Const.Value lhs = evalValue(t.lhs());
691    Const.Value rhs = evalValue(t.rhs());
692    switch (t.op()) {
693      case PLUS:
694        return add(lhs, rhs);
695      case MINUS:
696        return subtract(lhs, rhs);
697      case MULT:
698        return mult(lhs, rhs);
699      case DIVIDE:
700        return divide(lhs, rhs);
701      case MODULO:
702        return mod(lhs, rhs);
703      case SHIFT_LEFT:
704        return shiftLeft(lhs, rhs);
705      case SHIFT_RIGHT:
706        return shiftRight(lhs, rhs);
707      case UNSIGNED_SHIFT_RIGHT:
708        return unsignedShiftRight(lhs, rhs);
709      case LESS_THAN:
710        return lessThan(lhs, rhs);
711      case GREATER_THAN:
712        return greaterThan(lhs, rhs);
713      case LESS_THAN_EQ:
714        return lessThanEqual(lhs, rhs);
715      case GREATER_THAN_EQ:
716        return greaterThanEqual(lhs, rhs);
717      case EQUAL:
718        return equal(lhs, rhs);
719      case NOT_EQUAL:
720        return notEqual(lhs, rhs);
721      case AND:
722        return new Const.BooleanValue(lhs.asBoolean().value() && rhs.asBoolean().value());
723      case OR:
724        return new Const.BooleanValue(lhs.asBoolean().value() || rhs.asBoolean().value());
725      case BITWISE_AND:
726        return bitwiseAnd(lhs, rhs);
727      case BITWISE_XOR:
728        return bitwiseXor(lhs, rhs);
729      case BITWISE_OR:
730        return bitwiseOr(lhs, rhs);
731      default:
732        throw new AssertionError(t.op());
733    }
734  }
735
736  private static Const.Value promoteUnary(Const.Value v) {
737    switch (v.constantTypeKind()) {
738      case CHAR:
739      case SHORT:
740      case BYTE:
741        return v.asInteger();
742      case INT:
743      case LONG:
744      case FLOAT:
745      case DOUBLE:
746        return v;
747      default:
748        throw new AssertionError(v.constantTypeKind());
749    }
750  }
751
752  private static TurbineConstantTypeKind promoteBinary(Const.Value a, Const.Value b) {
753    a = promoteUnary(a);
754    b = promoteUnary(b);
755    switch (a.constantTypeKind()) {
756      case INT:
757        switch (b.constantTypeKind()) {
758          case INT:
759          case LONG:
760          case DOUBLE:
761          case FLOAT:
762            return b.constantTypeKind();
763          default:
764            throw new AssertionError(b.constantTypeKind());
765        }
766      case LONG:
767        switch (b.constantTypeKind()) {
768          case INT:
769            return TurbineConstantTypeKind.LONG;
770          case LONG:
771          case DOUBLE:
772          case FLOAT:
773            return b.constantTypeKind();
774          default:
775            throw new AssertionError(b.constantTypeKind());
776        }
777      case FLOAT:
778        switch (b.constantTypeKind()) {
779          case INT:
780          case LONG:
781          case FLOAT:
782            return TurbineConstantTypeKind.FLOAT;
783          case DOUBLE:
784            return TurbineConstantTypeKind.DOUBLE;
785          default:
786            throw new AssertionError(b.constantTypeKind());
787        }
788      case DOUBLE:
789        switch (b.constantTypeKind()) {
790          case INT:
791          case LONG:
792          case FLOAT:
793          case DOUBLE:
794            return TurbineConstantTypeKind.DOUBLE;
795          default:
796            throw new AssertionError(b.constantTypeKind());
797        }
798      default:
799        throw new AssertionError(a.constantTypeKind());
800    }
801  }
802
803  /**
804   * Evaluates annotation arguments given the symbol of the annotation declaration and a list of
805   * expression trees.
806   */
807  AnnoInfo evaluateAnnotation(ClassSymbol sym, ImmutableList<Expression> args) {
808    Map<String, Type> template = new LinkedHashMap<>();
809    for (MethodInfo method : env.get(sym).methods()) {
810      template.put(method.name(), method.returnType());
811    }
812
813    ImmutableMap.Builder<String, Const> values = ImmutableMap.builder();
814    for (Expression arg : args) {
815      Expression expr;
816      String key;
817      if (arg.kind() == Tree.Kind.ASSIGN) {
818        Tree.Assign assign = (Tree.Assign) arg;
819        key = assign.name();
820        expr = assign.expr();
821      } else {
822        // expand the implicit 'value' name; `@Foo(42)` is sugar for `@Foo(value=42)`
823        key = "value";
824        expr = arg;
825      }
826      Type ty = template.get(key);
827      Const value = evalAnnotationValue(expr, ty);
828      values.put(key, value);
829    }
830    return new AnnoInfo(sym, args, values.build());
831  }
832
833  private Const.AnnotationValue evalAnno(Tree.Anno t) {
834    LookupResult result = owner.scope().lookup(new LookupKey(t.name()));
835    ClassSymbol sym = (ClassSymbol) result.sym();
836    for (String name : result.remaining()) {
837      sym = Resolve.resolve(env, sym, name);
838    }
839    AnnoInfo annoInfo = evaluateAnnotation(sym, t.args());
840    return new Const.AnnotationValue(annoInfo.sym(), annoInfo.values());
841  }
842
843  private Const.ArrayInitValue evalArrayInit(ArrayInit t) {
844    ImmutableList.Builder<Const> elements = ImmutableList.builder();
845    for (Expression e : t.exprs()) {
846      elements.add(eval(e));
847    }
848    return new Const.ArrayInitValue(elements.build());
849  }
850
851  Const evalAnnotationValue(Tree tree, Type ty) {
852    Const value = eval(tree);
853    switch (ty.tyKind()) {
854      case PRIM_TY:
855        return coerce((Const.Value) value, ((Type.PrimTy) ty).primkind());
856      case CLASS_TY:
857      case TY_VAR:
858        return value;
859      case ARRAY_TY:
860        {
861          if (value.kind() == Const.Kind.ARRAY) {
862            return value;
863          }
864          Type.ArrayTy aty = (Type.ArrayTy) ty;
865          return new Const.ArrayInitValue(ImmutableList.of(cast(aty.elementType(), value)));
866        }
867      default:
868        throw new AssertionError(ty.tyKind());
869    }
870  }
871}
872