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