Merge "Remove unnecessary folders in error_test"
diff --git a/AST.h b/AST.h
index 1fe514f..dc39c0a 100644
--- a/AST.h
+++ b/AST.h
@@ -31,13 +31,15 @@
 namespace android {
 
 struct Coordinator;
+struct EnumValue;
 struct Formatter;
 struct Interface;
 struct Location;
 struct Method;
 struct NamedType;
-struct TypedVar;
-struct EnumValue;
+template <class T>
+struct NamedReference;
+struct Type;
 
 struct AST {
     AST(const Coordinator *coordinator, const std::string &path);
@@ -242,35 +244,20 @@
             InstrumentationEvent event,
             const Method *method) const;
 
-    void declareCppReaderLocals(
-            Formatter &out,
-            const std::vector<TypedVar *> &arg,
-            bool forResults) const;
+    void declareCppReaderLocals(Formatter& out, const std::vector<NamedReference<Type>*>& arg,
+                                bool forResults) const;
 
-    void emitCppReaderWriter(
-            Formatter &out,
-            const std::string &parcelObj,
-            bool parcelObjIsPointer,
-            const TypedVar *arg,
-            bool isReader,
-            Type::ErrorMode mode,
-            bool addPrefixToName) const;
+    void emitCppReaderWriter(Formatter& out, const std::string& parcelObj, bool parcelObjIsPointer,
+                             const NamedReference<Type>* arg, bool isReader, Type::ErrorMode mode,
+                             bool addPrefixToName) const;
 
-    void emitCppResolveReferences(
-            Formatter &out,
-            const std::string &parcelObj,
-            bool parcelObjIsPointer,
-            const TypedVar *arg,
-            bool isReader,
-            Type::ErrorMode mode,
-            bool addPrefixToName) const;
+    void emitCppResolveReferences(Formatter& out, const std::string& parcelObj,
+                                  bool parcelObjIsPointer, const NamedReference<Type>* arg,
+                                  bool isReader, Type::ErrorMode mode, bool addPrefixToName) const;
 
-    void emitJavaReaderWriter(
-            Formatter &out,
-            const std::string &parcelObj,
-            const TypedVar *arg,
-            bool isReader,
-            bool addPrefixToName) const;
+    void emitJavaReaderWriter(Formatter& out, const std::string& parcelObj,
+                              const NamedReference<Type>* arg, bool isReader,
+                              bool addPrefixToName) const;
 
     status_t emitTypeDeclarations(Formatter &out) const;
     status_t emitJavaTypeDeclarations(Formatter &out) const;
diff --git a/CompoundType.cpp b/CompoundType.cpp
index da30747..146074e 100644
--- a/CompoundType.cpp
+++ b/CompoundType.cpp
@@ -31,8 +31,7 @@
     return mStyle;
 }
 
-bool CompoundType::setFields(
-        std::vector<CompoundField *> *fields, std::string *errorMsg) {
+bool CompoundType::setFields(std::vector<NamedReference<Type>*>* fields, std::string* errorMsg) {
     mFields = fields;
 
     for (const auto &field : *fields) {
@@ -522,7 +521,7 @@
             << "std::string os;\n";
         out << "os += \"{\";\n";
 
-        for (const CompoundField *field : *mFields) {
+        for (const NamedReference<Type>* field : *mFields) {
             out << "os += \"";
             if (field != *(mFields->begin())) {
                 out << ", ";
@@ -1113,20 +1112,5 @@
     }
 }
 
-////////////////////////////////////////////////////////////////////////////////
-
-CompoundField::CompoundField(const char* name, const Reference<Type>& type)
-    : mName(name), mType(type) {
-    CHECK(!type.isEmptyReference());
-}
-
-std::string CompoundField::name() const {
-    return mName;
-}
-
-const Type &CompoundField::type() const {
-    return *(mType.get());
-}
-
 }  // namespace android
 
diff --git a/CompoundType.h b/CompoundType.h
index 2674544..da986a1 100644
--- a/CompoundType.h
+++ b/CompoundType.h
@@ -25,8 +25,6 @@
 
 namespace android {
 
-struct CompoundField;
-
 struct CompoundType : public Scope {
     enum Style {
         STYLE_STRUCT,
@@ -37,7 +35,7 @@
 
     Style style() const;
 
-    bool setFields(std::vector<CompoundField *> *fields, std::string *errorMsg);
+    bool setFields(std::vector<NamedReference<Type>*>* fields, std::string* errorMsg);
 
     bool isCompoundType() const override;
 
@@ -137,7 +135,7 @@
 
 private:
     Style mStyle;
-    std::vector<CompoundField *> *mFields;
+    std::vector<NamedReference<Type>*>* mFields;
 
     void emitStructReaderWriter(
             Formatter &out, const std::string &prefix, bool isReader) const;
@@ -147,19 +145,6 @@
     DISALLOW_COPY_AND_ASSIGN(CompoundType);
 };
 
-struct CompoundField {
-    CompoundField(const char* name, const Reference<Type>& type);
-
-    std::string name() const;
-    const Type &type() const;
-
-private:
-    std::string mName;
-    Reference<Type> mType;
-
-    DISALLOW_COPY_AND_ASSIGN(CompoundField);
-};
-
 }  // namespace android
 
 #endif  // COMPOUND_TYPE_H_
diff --git a/ConstantExpression.cpp b/ConstantExpression.cpp
index eba28e1..265f841 100644
--- a/ConstantExpression.cpp
+++ b/ConstantExpression.cpp
@@ -23,14 +23,14 @@
 #include <sstream>
 
 #include "EnumType.h"
+#include "Scope.h"  // LocalIdentifier
 
 // The macros are really nasty here. Consider removing
 // as many macros as possible.
 
-#define STREQ(__x__, __y__) (strcmp((__x__), (__y__)) == 0)
-#define OPEQ(__y__) STREQ(op, __y__)
-#define COMPUTE_UNARY(__op__)  if(OPEQ(#__op__)) return __op__ val;
-#define COMPUTE_BINARY(__op__) if(OPEQ(#__op__)) return lval __op__ rval;
+#define OPEQ(__y__) (std::string(mOp) == std::string(__y__))
+#define COMPUTE_UNARY(__op__)  if (op == std::string(#__op__)) return __op__ val;
+#define COMPUTE_BINARY(__op__) if (op == std::string(#__op__)) return lval __op__ rval;
 #define OP_IS_BIN_ARITHMETIC  (OPEQ("+") || OPEQ("-") || OPEQ("*") || OPEQ("/") || OPEQ("%"))
 #define OP_IS_BIN_BITFLIP     (OPEQ("|") || OPEQ("^") || OPEQ("&"))
 #define OP_IS_BIN_COMP        (OPEQ("<") || OPEQ(">") || OPEQ("<=") || OPEQ(">=") || OPEQ("==") || OPEQ("!="))
@@ -96,7 +96,7 @@
 }
 
 template <class T>
-T handleUnary(const char *op, T val) {
+T handleUnary(const std::string& op, T val) {
     COMPUTE_UNARY(+)
     COMPUTE_UNARY(-)
     COMPUTE_UNARY(!)
@@ -107,7 +107,7 @@
 }
 
 template <class T>
-T handleBinaryCommon(T lval, const char *op, T rval) {
+T handleBinaryCommon(T lval, const std::string& op, T rval) {
     COMPUTE_BINARY(+)
     COMPUTE_BINARY(-)
     COMPUTE_BINARY(*)
@@ -130,85 +130,70 @@
 }
 
 template <class T>
-T handleShift(T lval, const char *op, int64_t rval) {
+T handleShift(T lval, const std::string& op, int64_t rval) {
     // just cast rval to int64_t and it should fit.
     COMPUTE_BINARY(>>)
     COMPUTE_BINARY(<<)
     // Should not reach here.
-    SHOULD_NOT_REACH() << "Could not handleShift for"
+    SHOULD_NOT_REACH() << "Could not handleShift for "
                        << lval << " " << op << " " << rval;
     return static_cast<T>(0xdeadbeef);
 }
 
-bool handleLogical(bool lval, const char *op, bool rval) {
+bool handleLogical(bool lval, const std::string& op, bool rval) {
     COMPUTE_BINARY(||);
     COMPUTE_BINARY(&&);
     // Should not reach here.
-    SHOULD_NOT_REACH() << "Could not handleLogical for"
+    SHOULD_NOT_REACH() << "Could not handleLogical for "
                        << lval << " " << op << " " << rval;
     return false;
 }
 
-ConstantExpression::ConstantExpression() {
+std::unique_ptr<ConstantExpression> ConstantExpression::Zero(ScalarType::Kind kind) {
+    return ValueOf(kind, 0);
 }
 
-ConstantExpression ConstantExpression::Zero(ScalarType::Kind kind) {
-    ConstantExpression ce = ValueOf(kind, 0);
-    ce.mExpr = "0";
-    return ce;
+std::unique_ptr<ConstantExpression> ConstantExpression::One(ScalarType::Kind kind) {
+    return ValueOf(kind, 1);
 }
 
-ConstantExpression ConstantExpression::One(ScalarType::Kind kind) {
-    ConstantExpression ce = ValueOf(kind, 1);
-    ce.mExpr = "1";
-    return ce;
+std::unique_ptr<ConstantExpression> ConstantExpression::ValueOf(ScalarType::Kind kind,
+                                                                uint64_t value) {
+    return std::make_unique<LiteralConstantExpression>(kind, value);
 }
 
-ConstantExpression ConstantExpression::ValueOf(ScalarType::Kind kind, uint64_t value) {
-    ConstantExpression ce;
+bool ConstantExpression::isEvaluated() const {
+    return mIsEvaluated;
+}
+
+LiteralConstantExpression::LiteralConstantExpression(ScalarType::Kind kind, uint64_t value) {
     CHECK(isSupported(kind));
-
-    ce.mExpr = "";
-    ce.mType = kConstExprLiteral;
-    ce.mValueKind = kind;
-    ce.mValue = value;
-    ce.mTrivialDescription = true;
-    return ce;
-}
-ConstantExpression::ConstantExpression(const ConstantExpression& other) {
-    *this = other;
+    mTrivialDescription = true;
+    mExpr = std::to_string(value);
+    mValueKind = kind;
+    mValue = value;
+    mIsEvaluated = true;
 }
 
-/* Copy constructor, with the expr overriden and treated non-trivial */
-ConstantExpression::ConstantExpression(const ConstantExpression& other, std::string expr) {
-    *this = other;
-    mExpr = expr;
-    mTrivialDescription = false;
-}
+LiteralConstantExpression::LiteralConstantExpression(const std::string& value) {
+    CHECK(!value.empty());
+    mIsEvaluated = true;
+    mTrivialDescription = true;
+    mExpr = value;
 
-ConstantExpression& ConstantExpression::operator=(const ConstantExpression& other) {
-    mType = other.mType;
-    mValueKind = other.mValueKind;
-    mValue = other.mValue;
-    mExpr = other.mExpr;
-    mTrivialDescription = other.mTrivialDescription;
-    return *this;
-}
-
-/* Literals. */
-ConstantExpression::ConstantExpression(const char *value)
-        : mExpr(value), mType(kConstExprLiteral), mTrivialDescription(true) {
-    const char* head = value, *tail = head + strlen(value) - 1;
     bool isLong = false, isUnsigned = false;
-    bool isHex = (value[0] == '0' && (value[1] == 'x' || value[1] == 'X'));
-    while(tail >= head && (*tail == 'u' || *tail == 'U' || *tail == 'l' || *tail == 'L')) {
-        isUnsigned |= (*tail == 'u' || *tail == 'U');
-        isLong     |= (*tail == 'l' || *tail == 'L');
-        tail--;
+    bool isHex = (value[0] == '0' && value.length() > 1 && (value[1] == 'x' || value[1] == 'X'));
+
+    auto rbegin = value.rbegin();
+    auto rend = value.rend();
+    for (; rbegin != rend && (*rbegin == 'u' || *rbegin == 'U' || *rbegin == 'l' || *rbegin == 'L');
+         ++rbegin) {
+        isUnsigned |= (*rbegin == 'u' || *rbegin == 'U');
+        isLong |= (*rbegin == 'l' || *rbegin == 'L');
     }
-    char *newVal = strndup(value, tail - head + 1);
+    std::string newVal(value.begin(), rbegin.base());
+    CHECK(!newVal.empty());
     bool parseOK = base::ParseUint(newVal, &mValue);
-    free(newVal);
     CHECK(parseOK) << "Could not parse as integer: " << value;
 
     // guess literal type.
@@ -243,60 +228,70 @@
     }
 }
 
-/* Unary operations. */
-ConstantExpression::ConstantExpression(const char *op,
-                                       const ConstantExpression *value)
-        : mExpr(std::string("(") + op + value->mExpr + ")"),
-          mType(kConstExprUnary),
-          mValueKind(value->mValueKind) {
+void LiteralConstantExpression::evaluate() {
+    // Evaluated in constructor
+    CHECK(isEvaluated());
+}
 
-#define CASE_UNARY(__type__)\
-            mValue = handleUnary(op, static_cast<__type__>(value->mValue)); return;
+void UnaryConstantExpression::evaluate() {
+    if (isEvaluated()) return;
+    mUnary->evaluate();
+    mIsEvaluated = true;
+
+    mExpr = std::string("(") + mOp + mUnary->description() + ")";
+    mValueKind = mUnary->mValueKind;
+
+#define CASE_UNARY(__type__)                                          \
+    mValue = handleUnary(mOp, static_cast<__type__>(mUnary->mValue)); \
+    return;
 
     SWITCH_KIND(mValueKind, CASE_UNARY, SHOULD_NOT_REACH(); return;)
 }
 
-/* Binary operations. */
-ConstantExpression::ConstantExpression(const ConstantExpression *lval,
-                                       const char *op,
-                                       const ConstantExpression* rval)
-        : mExpr(std::string("(") + lval->mExpr + " " + op + " " + rval->mExpr + ")"),
-          mType(kConstExprBinary)
-{
+void BinaryConstantExpression::evaluate() {
+    if (isEvaluated()) return;
+    mLval->evaluate();
+    mRval->evaluate();
+    mIsEvaluated = true;
+
+    mExpr = std::string("(") + mLval->description() + " " + mOp + " " + mRval->description() + ")";
 
     bool isArithmeticOrBitflip = OP_IS_BIN_ARITHMETIC || OP_IS_BIN_BITFLIP;
 
     // CASE 1: + - *  / % | ^ & < > <= >= == !=
     if(isArithmeticOrBitflip || OP_IS_BIN_COMP) {
         // promoted kind for both operands.
-        ScalarType::Kind promoted = usualArithmeticConversion(
-                integralPromotion(lval->mValueKind),
-                integralPromotion(rval->mValueKind));
+        ScalarType::Kind promoted = usualArithmeticConversion(integralPromotion(mLval->mValueKind),
+                                                              integralPromotion(mRval->mValueKind));
         // result kind.
         mValueKind = isArithmeticOrBitflip
                     ? promoted // arithmetic or bitflip operators generates promoted type
                     : SK(BOOL); // comparison operators generates bool
 
-#define CASE_BINARY_COMMON(__type__)\
-            mValue = handleBinaryCommon(static_cast<__type__>(lval->mValue), op, static_cast<__type__>(rval->mValue)); return;
+#define CASE_BINARY_COMMON(__type__)                                       \
+    mValue = handleBinaryCommon(static_cast<__type__>(mLval->mValue), mOp, \
+                                static_cast<__type__>(mRval->mValue));     \
+    return;
 
         SWITCH_KIND(promoted, CASE_BINARY_COMMON, SHOULD_NOT_REACH(); return;)
     }
 
     // CASE 2: << >>
+    std::string newOp = mOp;
     if(OP_IS_BIN_SHIFT) {
-        mValueKind = integralPromotion(lval->mValueKind);
+        mValueKind = integralPromotion(mLval->mValueKind);
         // instead of promoting rval, simply casting it to int64 should also be good.
-        int64_t numBits = rval->cast<int64_t>();
+        int64_t numBits = mRval->cast<int64_t>();
         if(numBits < 0) {
             // shifting with negative number of bits is undefined in C. In HIDL it
             // is defined as shifting into the other direction.
-            op = OPEQ("<<") ? ">>" : "<<";
+            newOp = OPEQ("<<") ? std::string(">>") : std::string("<<");
             numBits = -numBits;
         }
 
-#define CASE_SHIFT(__type__)\
-            mValue = handleShift(static_cast<__type__>(lval->mValue), op, numBits); return;
+#define CASE_SHIFT(__type__)                                                    \
+    mValue = handleShift(static_cast<__type__>(mLval->mValue), newOp, numBits); \
+    return;
 
         SWITCH_KIND(mValueKind, CASE_SHIFT, SHOULD_NOT_REACH(); return;)
     }
@@ -305,63 +300,80 @@
     if(OP_IS_BIN_LOGICAL) {
         mValueKind = SK(BOOL);
         // easy; everything is bool.
-        mValue = handleLogical(lval->mValue, op, rval->mValue);
+        mValue = handleLogical(mLval->mValue, mOp, mRval->mValue);
         return;
     }
 
     SHOULD_NOT_REACH();
 }
 
-/* Ternary ?: operation. */
-ConstantExpression::ConstantExpression(const ConstantExpression *cond,
-                                       const ConstantExpression *trueVal,
-                                       const ConstantExpression *falseVal)
-        : mExpr(std::string("(") + cond->mExpr + "?" + trueVal->mExpr
-                + ":" + falseVal->mExpr + ")"),
-          mType(kConstExprTernary) {
+void TernaryConstantExpression::evaluate() {
+    if (isEvaluated()) return;
+    mCond->evaluate();
+    mTrueVal->evaluate();
+    mFalseVal->evaluate();
+    mIsEvaluated = true;
+
+    mExpr = std::string("(") + mCond->description() + "?" + mTrueVal->description() + ":" +
+            mFalseVal->description() + ")";
 
     // note: for ?:, unlike arithmetic ops, integral promotion is not necessary.
-    mValueKind = usualArithmeticConversion(trueVal->mValueKind,
-                                           falseVal->mValueKind);
+    mValueKind = usualArithmeticConversion(mTrueVal->mValueKind, mFalseVal->mValueKind);
 
-#define CASE_TERNARY(__type__)\
-        mValue = cond->mValue ? (static_cast<__type__>(trueVal->mValue)) : (static_cast<__type__>(falseVal->mValue)); return;
+#define CASE_TERNARY(__type__)                                           \
+    mValue = mCond->mValue ? (static_cast<__type__>(mTrueVal->mValue))   \
+                           : (static_cast<__type__>(mFalseVal->mValue)); \
+    return;
 
     SWITCH_KIND(mValueKind, CASE_TERNARY, SHOULD_NOT_REACH(); return;)
 }
 
-ConstantExpression ConstantExpression::addOne() const {
-    ConstantExpression myOne = ConstantExpression::One(mValueKind);
-    return ConstantExpression(this, "+", &myOne).toLiteral();
+void ReferenceConstantExpression::evaluate() {
+    if (isEvaluated()) return;
+
+    ConstantExpression* expr = mReference->constExpr();
+    CHECK(expr != nullptr);
+    expr->evaluate();
+
+    mValueKind = expr->mValueKind;
+    mValue = expr->mValue;
+    mIsEvaluated = true;
 }
 
-ConstantExpression &ConstantExpression::toLiteral() {
-    mExpr = value();
-    mType = kConstExprLiteral;
-    return *this;
+std::unique_ptr<ConstantExpression> ConstantExpression::addOne(ScalarType::Kind baseKind) {
+    auto ret = std::make_unique<BinaryConstantExpression>(
+        this, "+", ConstantExpression::One(baseKind).release());
+    ret->mTrivialDescription = true;
+    return ret;
 }
 
-const std::string &ConstantExpression::description() const {
+const std::string& ConstantExpression::description() const {
+    CHECK(isEvaluated());
     return mExpr;
 }
 
 bool ConstantExpression::descriptionIsTrivial() const {
+    CHECK(isEvaluated());
     return mTrivialDescription;
 }
 
 std::string ConstantExpression::value() const {
+    CHECK(isEvaluated());
     return rawValue(mValueKind);
 }
 
 std::string ConstantExpression::value(ScalarType::Kind castKind) const {
+    CHECK(isEvaluated());
     return rawValue(castKind);
 }
 
 std::string ConstantExpression::cppValue() const {
+    CHECK(isEvaluated());
     return cppValue(mValueKind);
 }
 
 std::string ConstantExpression::cppValue(ScalarType::Kind castKind) const {
+    CHECK(isEvaluated());
     std::string literal(rawValue(castKind));
     // this is a hack to translate
     //       enum x : int64_t {  y = 1l << 63 };
@@ -384,10 +396,12 @@
 }
 
 std::string ConstantExpression::javaValue() const {
+    CHECK(isEvaluated());
     return javaValue(mValueKind);
 }
 
 std::string ConstantExpression::javaValue(ScalarType::Kind castKind) const {
+    CHECK(isEvaluated());
     switch(castKind) {
         case SK(UINT64): return rawValue(SK(INT64)) + "L";
         case SK(INT64):  return rawValue(SK(INT64)) + "L";
@@ -402,6 +416,7 @@
 }
 
 std::string ConstantExpression::rawValue(ScalarType::Kind castKind) const {
+    CHECK(isEvaluated());
 
 #define CASE_STR(__type__) return std::to_string(this->cast<__type__>());
 
@@ -410,6 +425,7 @@
 
 template<typename T>
 T ConstantExpression::cast() const {
+    CHECK(isEvaluated());
 
 #define CASE_CAST_T(__type__) return static_cast<T>(static_cast<__type__>(mValue));
 
@@ -417,9 +433,28 @@
 }
 
 size_t ConstantExpression::castSizeT() const {
+    CHECK(isEvaluated());
     return this->cast<size_t>();
 }
 
+UnaryConstantExpression::UnaryConstantExpression(const std::string& op, ConstantExpression* value)
+    : mUnary(value), mOp(op) {}
+
+BinaryConstantExpression::BinaryConstantExpression(ConstantExpression* lval, const std::string& op,
+                                                   ConstantExpression* rval)
+    : mLval(lval), mRval(rval), mOp(op) {}
+
+TernaryConstantExpression::TernaryConstantExpression(ConstantExpression* cond,
+                                                     ConstantExpression* trueVal,
+                                                     ConstantExpression* falseVal)
+    : mCond(cond), mTrueVal(trueVal), mFalseVal(falseVal) {}
+
+ReferenceConstantExpression::ReferenceConstantExpression(const Reference<LocalIdentifier>& value,
+                                                         const std::string& expr)
+    : mReference(value) {
+    mExpr = expr;
+}
+
 /*
 
 Evaluating expressions in HIDL language
diff --git a/ConstantExpression.h b/ConstantExpression.h
index 2c955d4..ebb6c48 100644
--- a/ConstantExpression.h
+++ b/ConstantExpression.h
@@ -19,45 +19,41 @@
 #define CONSTANT_EXPRESSION_H_
 
 #include <android-base/macros.h>
+#include <memory>
 #include <string>
+
+#include "Reference.h"
 #include "ScalarType.h"
 
 namespace android {
 
+struct LocalIdentifier;
+
+struct LiteralConstantExpression;
+struct UnaryConstantExpression;
+struct BinaryConstantExpression;
+struct TernaryConstantExpression;
+struct ReferenceConstantExpression;
+
 /**
  * A constant expression is represented by a tree.
  */
 struct ConstantExpression {
+    static std::unique_ptr<ConstantExpression> Zero(ScalarType::Kind kind);
+    static std::unique_ptr<ConstantExpression> One(ScalarType::Kind kind);
+    static std::unique_ptr<ConstantExpression> ValueOf(ScalarType::Kind kind, uint64_t value);
 
-    enum ConstExprType {
-        kConstExprLiteral,
-        kConstExprUnary,
-        kConstExprBinary,
-        kConstExprTernary
-    };
+    virtual ~ConstantExpression() {}
 
-    /* Default constructor. */
-    ConstantExpression();
-    /* Copy constructor. */
-    ConstantExpression(const ConstantExpression& other);
-    /* Copy constructor, with the expr overriden. */
-    ConstantExpression(const ConstantExpression& other, std::string expr);
-    /* Literals */
-    ConstantExpression(const char *value);
-    /* binary operations */
-    ConstantExpression(const ConstantExpression *value1,
-        const char *op, const ConstantExpression* value2);
-    /* unary operations */
-    ConstantExpression(const char *op, const ConstantExpression *value);
-    /* ternary ?: */
-    ConstantExpression(const ConstantExpression *cond,
-                       const ConstantExpression *trueVal,
-                       const ConstantExpression *falseVal);
+    /*
+     * Runs recursive evaluation.
+     * Provides sort of lazy computation,
+     * mainly used for forward identifier reference.
+     */
+    virtual void evaluate() = 0;
 
-    static ConstantExpression Zero(ScalarType::Kind kind);
-    static ConstantExpression One(ScalarType::Kind kind);
-    static ConstantExpression ValueOf(ScalarType::Kind kind, uint64_t value);
-
+    /* Returns true iff the value has already been evaluated. */
+    bool isEvaluated() const;
     /* Evaluated result in a string form. */
     std::string value() const;
     /* Evaluated result in a string form. */
@@ -70,22 +66,21 @@
     std::string cppValue(ScalarType::Kind castKind) const;
     /* Evaluated result in a string form, with given contextual kind. */
     std::string javaValue(ScalarType::Kind castKind) const;
-    /* Original expression with type. */
-    const std::string &description() const;
+    /* Formatted expression with type. */
+    const std::string& description() const;
     /* See mTrivialDescription */
     bool descriptionIsTrivial() const;
     /* Return a ConstantExpression that is 1 plus the original. */
-    ConstantExpression addOne() const;
-    /* Assignment operator. */
-    ConstantExpression& operator=(const ConstantExpression& other);
+    std::unique_ptr<ConstantExpression> addOne(ScalarType::Kind baseKind);
 
     size_t castSizeT() const;
 
-private:
+   private:
+    /* If the result value has been evaluated. */
+    bool mIsEvaluated = false;
+
     /* The formatted expression. */
     std::string mExpr;
-    /* The type of the expression. Hints on its original form. */
-    ConstExprType mType;
     /* The kind of the result value. */
     ScalarType::Kind mValueKind;
     /* The stored result value. */
@@ -99,15 +94,65 @@
      * digits) converted from mValue.
      */
     std::string rawValue(ScalarType::Kind castKind) const;
-    /* Trim unnecessary information. Only mValue and mValueKind is kept. */
-    ConstantExpression &toLiteral();
 
     /*
      * Return the value casted to the given type.
      * First cast it according to mValueKind, then cast it to T.
      * Assumes !containsIdentifiers()
      */
-    template <typename T> T cast() const;
+    template <typename T>
+    T cast() const;
+
+    friend struct LiteralConstantExpression;
+    friend struct UnaryConstantExpression;
+    friend struct BinaryConstantExpression;
+    friend struct TernaryConstantExpression;
+    friend struct ReferenceConstantExpression;
+};
+
+struct LiteralConstantExpression : public ConstantExpression {
+    LiteralConstantExpression(ScalarType::Kind kind, uint64_t value);
+    LiteralConstantExpression(const std::string& value);
+    void evaluate() override;
+};
+
+struct UnaryConstantExpression : public ConstantExpression {
+    UnaryConstantExpression(const std::string& mOp, ConstantExpression* value);
+    void evaluate() override;
+
+   private:
+    ConstantExpression* const mUnary;
+    std::string mOp;
+};
+
+struct BinaryConstantExpression : public ConstantExpression {
+    BinaryConstantExpression(ConstantExpression* lval, const std::string& op,
+                             ConstantExpression* rval);
+    void evaluate() override;
+
+   private:
+    ConstantExpression* const mLval;
+    ConstantExpression* const mRval;
+    const std::string mOp;
+};
+
+struct TernaryConstantExpression : public ConstantExpression {
+    TernaryConstantExpression(ConstantExpression* cond, ConstantExpression* trueVal,
+                              ConstantExpression* falseVal);
+    void evaluate() override;
+
+   private:
+    ConstantExpression* const mCond;
+    ConstantExpression* const mTrueVal;
+    ConstantExpression* const mFalseVal;
+};
+
+struct ReferenceConstantExpression : public ConstantExpression {
+    ReferenceConstantExpression(const Reference<LocalIdentifier>& value, const std::string& expr);
+    void evaluate() override;
+
+   private:
+    Reference<LocalIdentifier> mReference;
 };
 
 }  // namespace android
diff --git a/EnumType.cpp b/EnumType.cpp
index 9f70287..02c6c69 100644
--- a/EnumType.cpp
+++ b/EnumType.cpp
@@ -692,18 +692,16 @@
     return mValue;
 }
 
-void EnumValue::autofill(const EnumValue *prev, const ScalarType *type) {
-    if(mValue != nullptr)
-        return;
+void EnumValue::autofill(const EnumValue* prev, const ScalarType* type) {
+    if (mValue != nullptr) return;
     mIsAutoFill = true;
-    ConstantExpression *value = new ConstantExpression();
-    if(prev == nullptr) {
-        *value = ConstantExpression::Zero(type->getKind());
+    if (prev == nullptr) {
+        mValue = ConstantExpression::Zero(type->getKind()).release();
     } else {
         CHECK(prev->mValue != nullptr);
-        *value = prev->mValue->addOne();
+        mValue = prev->mValue->addOne(type->getKind()).release();
     }
-    mValue = value;
+    mValue->evaluate();
 }
 
 bool EnumValue::isAutoFill() const {
diff --git a/EnumType.h b/EnumType.h
index 35db597..95a6174 100644
--- a/EnumType.h
+++ b/EnumType.h
@@ -131,14 +131,14 @@
     std::string javaValue(ScalarType::Kind castKind) const;
     std::string comment() const;
     void autofill(const EnumValue *prev, const ScalarType *type);
-    ConstantExpression *constExpr() const;
+    ConstantExpression* constExpr() const override;
 
     bool isAutoFill() const;
     bool isEnumValue() const override;
 
 
     std::string mName;
-    ConstantExpression *mValue;
+    ConstantExpression* mValue;
     bool mIsAutoFill;
 
     DISALLOW_COPY_AND_ASSIGN(EnumValue);
diff --git a/Interface.cpp b/Interface.cpp
index 805d81c..78d42ad 100644
--- a/Interface.cpp
+++ b/Interface.cpp
@@ -28,6 +28,7 @@
 #include <unistd.h>
 
 #include <iostream>
+#include <memory>
 #include <sstream>
 
 #include <android-base/logging.h>
@@ -287,10 +288,8 @@
 }
 
 static void emitDigestChain(
-        Formatter &out,
-        const std::string &prefix,
-        const std::vector<const Interface *> &chain,
-        std::function<std::string(const ConstantExpression &)> byteToString) {
+    Formatter& out, const std::string& prefix, const std::vector<const Interface*>& chain,
+    std::function<std::string(std::unique_ptr<ConstantExpression>)> byteToString) {
     out.join(chain.begin(), chain.end(), ",\n", [&] (const auto &iface) {
         const Hash &hash = Hash::getHash(iface->location().begin().filename());
         out << prefix;
@@ -319,8 +318,8 @@
             std::vector<const Interface *> chain = typeChain();
             out << "_hidl_cb(";
             out.block([&] {
-                emitDigestChain(out, "(" + digestType->getInternalDataCppType() + ")",
-                    chain, [](const auto &e){return e.cppValue();});
+                emitDigestChain(out, "(" + digestType->getInternalDataCppType() + ")", chain,
+                                [](const auto& e) { return e->cppValue(); });
             });
             out << ");\n";
             out << "return ::android::hardware::Void();\n";
@@ -333,7 +332,7 @@
             out.indent(2, [&] {
                 // No need for dimensions when elements are explicitly provided.
                 emitDigestChain(out, "new " + digestType->getJavaType(false /* forInitializer */),
-                    chain, [](const auto &e){return e.javaValue();});
+                                chain, [](const auto& e) { return e->javaValue(); });
             });
             out << "));\n";
         } } } /* javaImpl */
diff --git a/Method.cpp b/Method.cpp
index 5a3e248..48eb80e 100644
--- a/Method.cpp
+++ b/Method.cpp
@@ -22,20 +22,14 @@
 
 #include <android-base/logging.h>
 #include <hidl-util/Formatter.h>
+#include <algorithm>
 
 namespace android {
 
-Method::Method(const char *name,
-       std::vector<TypedVar *> *args,
-       std::vector<TypedVar *> *results,
-       bool oneway,
-       std::vector<Annotation *> *annotations)
-    : mName(name),
-      mArgs(args),
-      mResults(results),
-      mOneway(oneway),
-      mAnnotations(annotations) {
-}
+Method::Method(const char* name, std::vector<NamedReference<Type>*>* args,
+               std::vector<NamedReference<Type>*>* results, bool oneway,
+               std::vector<Annotation*>* annotations)
+    : mName(name), mArgs(args), mResults(results), mOneway(oneway), mAnnotations(annotations) {}
 
 void Method::fillImplementation(
         size_t serial,
@@ -57,11 +51,11 @@
     return mName;
 }
 
-const std::vector<TypedVar *> &Method::args() const {
+const std::vector<NamedReference<Type>*>& Method::args() const {
     return *mArgs;
 }
 
-const std::vector<TypedVar *> &Method::results() const {
+const std::vector<NamedReference<Type>*>& Method::results() const {
     return *mResults;
 }
 
@@ -121,7 +115,7 @@
 }
 
 void Method::generateCppReturnType(Formatter &out, bool specifyNamespaces) const {
-    const TypedVar *elidedReturn = canElideCallback();
+    const NamedReference<Type>* elidedReturn = canElideCallback();
     const std::string space = (specifyNamespaces ? "::android::hardware::" : "");
 
     if (elidedReturn == nullptr) {
@@ -149,9 +143,9 @@
     out << ")";
 }
 
-static void emitCppArgResultSignature(Formatter &out,
-                         const std::vector<TypedVar *> &args,
-                         bool specifyNamespaces) {
+static void emitCppArgResultSignature(Formatter& out,
+                                      const std::vector<NamedReference<Type>*>& args,
+                                      bool specifyNamespaces) {
     out.join(args.begin(), args.end(), ", ", [&](auto arg) {
         out << arg->type().getCppArgumentType(specifyNamespaces);
         out << " ";
@@ -159,7 +153,8 @@
     });
 }
 
-static void emitJavaArgResultSignature(Formatter &out, const std::vector<TypedVar *> &args) {
+static void emitJavaArgResultSignature(Formatter& out,
+                                       const std::vector<NamedReference<Type>*>& args) {
     out.join(args.begin(), args.end(), ", ", [&](auto arg) {
         out << arg->type().getJavaType();
         out << " ";
@@ -171,7 +166,7 @@
     emitCppArgResultSignature(out, args(), specifyNamespaces);
 
     const bool returnsValue = !results().empty();
-    const TypedVar *elidedReturn = canElideCallback();
+    const NamedReference<Type>* elidedReturn = canElideCallback();
     if (returnsValue && elidedReturn == nullptr) {
         if (!args().empty()) {
             out << ", ";
@@ -210,28 +205,26 @@
         return true;
     }
 
-    for (const auto &arg : *mArgs) {
-        if (!arg->isJavaCompatible()) {
-            return false;
-        }
+    if (!std::all_of(mArgs->begin(), mArgs->end(),
+                     [](const auto* arg) { return (*arg)->isJavaCompatible(); })) {
+        return false;
     }
 
-    for (const auto &result : *mResults) {
-        if (!result->isJavaCompatible()) {
-            return false;
-        }
+    if (!std::all_of(mResults->begin(), mResults->end(),
+                     [](const auto* arg) { return (*arg)->isJavaCompatible(); })) {
+        return false;
     }
 
     return true;
 }
 
-const TypedVar* Method::canElideCallback() const {
+const NamedReference<Type>* Method::canElideCallback() const {
     // Can't elide callback for void or tuple-returning methods
     if (mResults->size() != 1) {
         return nullptr;
     }
 
-    const TypedVar *typedVar = mResults->at(0);
+    const NamedReference<Type>* typedVar = mResults->at(0);
 
     if (typedVar->type().isElidableType()) {
         return typedVar;
@@ -242,22 +235,7 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-TypedVar::TypedVar(const char* name, const Reference<Type>& type) : mName(name), mType(type) {}
-
-std::string TypedVar::name() const {
-    return mName;
-}
-
-const Type &TypedVar::type() const {
-    return *(mType.get());
-}
-
-bool TypedVar::isJavaCompatible() const {
-    return mType->isJavaCompatible();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-bool TypedVarVector::add(TypedVar *v) {
+bool TypedVarVector::add(NamedReference<Type>* v) {
     if (mNames.emplace(v->name()).second) {
         push_back(v);
         return true;
diff --git a/Method.h b/Method.h
index b77c66f..bb4e20d 100644
--- a/Method.h
+++ b/Method.h
@@ -34,7 +34,6 @@
 struct Formatter;
 struct ScalarType;
 struct Type;
-struct TypedVar;
 struct TypedVarVector;
 
 enum MethodImplType {
@@ -48,15 +47,13 @@
 using MethodImpl = std::map<MethodImplType, std::function<void(Formatter &)>>;
 
 struct Method {
-    Method(const char *name,
-           std::vector<TypedVar *> *args,
-           std::vector<TypedVar *> *results,
-           bool oneway,
-           std::vector<Annotation *> *annotations);
+    Method(const char* name, std::vector<NamedReference<Type>*>* args,
+           std::vector<NamedReference<Type>*>* results, bool oneway,
+           std::vector<Annotation*>* annotations);
 
     std::string name() const;
-    const std::vector<TypedVar *> &args() const;
-    const std::vector<TypedVar *> &results() const;
+    const std::vector<NamedReference<Type>*>& args() const;
+    const std::vector<NamedReference<Type>*>& results() const;
     bool isOneway() const { return mOneway; }
     bool overridesCppImpl(MethodImplType type) const;
     bool overridesJavaImpl(MethodImplType type) const;
@@ -92,7 +89,7 @@
     void emitJavaArgSignature(Formatter &out) const;
     void emitJavaResultSignature(Formatter &out) const;
 
-    const TypedVar* canElideCallback() const;
+    const NamedReference<Type>* canElideCallback() const;
 
     void dumpAnnotations(Formatter &out) const;
 
@@ -101,8 +98,8 @@
 private:
     std::string mName;
     size_t mSerial = 0;
-    std::vector<TypedVar *> *mArgs;
-    std::vector<TypedVar *> *mResults;
+    std::vector<NamedReference<Type>*>* mArgs;
+    std::vector<NamedReference<Type>*>* mResults;
     bool mOneway;
     std::vector<Annotation *> *mAnnotations;
 
@@ -115,26 +112,12 @@
     DISALLOW_COPY_AND_ASSIGN(Method);
 };
 
-struct TypedVar {
-    TypedVar(const char* name, const Reference<Type>& type);
-
-    std::string name() const;
-    const Type &type() const;
-
-    bool isJavaCompatible() const;
-
-private:
-    std::string mName;
-    Reference<Type> mType;
-
-    DISALLOW_COPY_AND_ASSIGN(TypedVar);
-};
-
-struct TypedVarVector : public std::vector<TypedVar *> {
+struct TypedVarVector : public std::vector<NamedReference<Type>*> {
     TypedVarVector() = default;
 
-    bool add(TypedVar *v);
-private:
+    bool add(NamedReference<Type>* v);
+
+   private:
     std::set<std::string> mNames;
 };
 
diff --git a/Reference.h b/Reference.h
index aab3b8f..afd74cb 100644
--- a/Reference.h
+++ b/Reference.h
@@ -105,6 +105,22 @@
     friend struct Reference;
 };
 
+template <class T>
+struct NamedReference {
+    NamedReference(const std::string& name, const Reference<T>& reference)
+        : mName(name), mReference(reference) {}
+
+    const std::string& name() const { return mName; }
+    const T& type() const { return *mReference.get(); }
+    const T* operator->() const { return mReference.get(); }
+
+   private:
+    const std::string mName;
+    const Reference<T> mReference;
+
+    DISALLOW_COPY_AND_ASSIGN(NamedReference<T>);
+};
+
 }  // namespace android
 
 #endif  // REFERENCE_H_
diff --git a/Scope.cpp b/Scope.cpp
index 13a6f28..1cee4f8 100644
--- a/Scope.cpp
+++ b/Scope.cpp
@@ -200,5 +200,9 @@
     return false;
 }
 
+ConstantExpression* LocalIdentifier::constExpr() const {
+    return nullptr;
+}
+
 }  // namespace android
 
diff --git a/Scope.h b/Scope.h
index 599182f..6a34a59 100644
--- a/Scope.h
+++ b/Scope.h
@@ -25,6 +25,7 @@
 
 namespace android {
 
+struct ConstantExpression;
 struct Formatter;
 struct Interface;
 struct LocalIdentifier;
@@ -88,6 +89,8 @@
     LocalIdentifier();
     virtual ~LocalIdentifier();
     virtual bool isEnumValue() const;
+
+    virtual ConstantExpression* constExpr() const;
 };
 
 }  // namespace android
diff --git a/generateCpp.cpp b/generateCpp.cpp
index 368f520..f2147b3 100644
--- a/generateCpp.cpp
+++ b/generateCpp.cpp
@@ -18,9 +18,10 @@
 
 #include "Coordinator.h"
 #include "EnumType.h"
-#include "Interface.h"
 #include "HidlTypeAssertion.h"
+#include "Interface.h"
 #include "Method.h"
+#include "Reference.h"
 #include "ScalarType.h"
 #include "Scope.h"
 
@@ -489,7 +490,7 @@
             out << "\n";
 
             const bool returnsValue = !method->results().empty();
-            const TypedVar *elidedReturn = method->canElideCallback();
+            const NamedReference<Type>* elidedReturn = method->canElideCallback();
 
             if (elidedReturn == nullptr && returnsValue) {
                 out << "using "
@@ -624,9 +625,8 @@
     return mRootScope.emitTypeDeclarations(out);
 }
 
-static void wrapPassthroughArg(Formatter &out,
-        const TypedVar *arg, bool addPrefixToName,
-        std::function<void(void)> handleError) {
+static void wrapPassthroughArg(Formatter& out, const NamedReference<Type>* arg,
+                               bool addPrefixToName, std::function<void(void)> handleError) {
     if (!arg->type().isInterface()) {
         return;
     }
@@ -670,7 +670,7 @@
     }
 
     const bool returnsValue = !method->results().empty();
-    const TypedVar *elidedReturn = method->canElideCallback();
+    const NamedReference<Type>* elidedReturn = method->canElideCallback();
 
     if (returnsValue && elidedReturn == nullptr) {
         generateCheckNonNull(out, "_hidl_cb");
@@ -932,7 +932,7 @@
             return OK;
         }
         const bool returnsValue = !method->results().empty();
-        const TypedVar *elidedReturn = method->canElideCallback();
+        const NamedReference<Type>* elidedReturn = method->canElideCallback();
 
         if (elidedReturn == nullptr && returnsValue) {
             out << "using " << method->name() << "_cb = "
@@ -1233,10 +1233,8 @@
     return mRootScope.emitTypeDefinitions(out, ifaceName);
 }
 
-void AST::declareCppReaderLocals(
-        Formatter &out,
-        const std::vector<TypedVar *> &args,
-        bool forResults) const {
+void AST::declareCppReaderLocals(Formatter& out, const std::vector<NamedReference<Type>*>& args,
+                                 bool forResults) const {
     if (args.empty()) {
         return;
     }
@@ -1253,14 +1251,9 @@
     out << "\n";
 }
 
-void AST::emitCppReaderWriter(
-        Formatter &out,
-        const std::string &parcelObj,
-        bool parcelObjIsPointer,
-        const TypedVar *arg,
-        bool isReader,
-        Type::ErrorMode mode,
-        bool addPrefixToName) const {
+void AST::emitCppReaderWriter(Formatter& out, const std::string& parcelObj, bool parcelObjIsPointer,
+                              const NamedReference<Type>* arg, bool isReader, Type::ErrorMode mode,
+                              bool addPrefixToName) const {
     const Type &type = arg->type();
 
     type.emitReaderWriter(
@@ -1272,14 +1265,10 @@
             mode);
 }
 
-void AST::emitCppResolveReferences(
-        Formatter &out,
-        const std::string &parcelObj,
-        bool parcelObjIsPointer,
-        const TypedVar *arg,
-        bool isReader,
-        Type::ErrorMode mode,
-        bool addPrefixToName) const {
+void AST::emitCppResolveReferences(Formatter& out, const std::string& parcelObj,
+                                   bool parcelObjIsPointer, const NamedReference<Type>* arg,
+                                   bool isReader, Type::ErrorMode mode,
+                                   bool addPrefixToName) const {
     const Type &type = arg->type();
     if(type.needsResolveReferences()) {
         type.emitResolveReferences(
@@ -1312,7 +1301,7 @@
 
     out.block([&] {
         const bool returnsValue = !method->results().empty();
-        const TypedVar *elidedReturn = method->canElideCallback();
+        const NamedReference<Type>* elidedReturn = method->canElideCallback();
 
         method->generateCppReturnType(out);
 
@@ -1380,7 +1369,7 @@
     out << "#endif // __ANDROID_DEBUGGABLE__\n";
 
     const bool returnsValue = !method->results().empty();
-    const TypedVar *elidedReturn = method->canElideCallback();
+    const NamedReference<Type>* elidedReturn = method->canElideCallback();
     if (returnsValue && elidedReturn == nullptr) {
         generateCheckNonNull(out, "_hidl_cb");
     }
@@ -1824,7 +1813,7 @@
             method);
 
     const bool returnsValue = !method->results().empty();
-    const TypedVar *elidedReturn = method->canElideCallback();
+    const NamedReference<Type>* elidedReturn = method->canElideCallback();
     const std::string callee = "static_cast<" + klassName + "*>(_hidl_this)->_hidl_mImpl";
 
     if (elidedReturn != nullptr) {
diff --git a/generateCppImpl.cpp b/generateCppImpl.cpp
index ae95590..90331b6 100644
--- a/generateCppImpl.cpp
+++ b/generateCppImpl.cpp
@@ -20,6 +20,7 @@
 #include "EnumType.h"
 #include "Interface.h"
 #include "Method.h"
+#include "Reference.h"
 #include "ScalarType.h"
 #include "Scope.h"
 
@@ -62,7 +63,7 @@
     out.indent();
     out << "// TODO implement\n";
 
-    const TypedVar *elidedReturn = method->canElideCallback();
+    const NamedReference<Type>* elidedReturn = method->canElideCallback();
 
     if (elidedReturn == nullptr) {
         out << "return Void();\n";
diff --git a/generateJava.cpp b/generateJava.cpp
index f463b7f..86e785c 100644
--- a/generateJava.cpp
+++ b/generateJava.cpp
@@ -19,6 +19,7 @@
 #include "Coordinator.h"
 #include "Interface.h"
 #include "Method.h"
+#include "Reference.h"
 #include "Scope.h"
 
 #include <hidl-util/Formatter.h>
@@ -26,12 +27,9 @@
 
 namespace android {
 
-void AST::emitJavaReaderWriter(
-        Formatter &out,
-        const std::string &parcelObj,
-        const TypedVar *arg,
-        bool isReader,
-        bool addPrefixToName) const {
+void AST::emitJavaReaderWriter(Formatter& out, const std::string& parcelObj,
+                               const NamedReference<Type>* arg, bool isReader,
+                               bool addPrefixToName) const {
     if (isReader) {
         out << arg->type().getJavaType()
             << " "
@@ -602,7 +600,7 @@
         }
 
         if (!needsCallback && returnsValue) {
-            const TypedVar *returnArg = method->results()[0];
+            const NamedReference<Type>* returnArg = method->results()[0];
 
             out << returnArg->type().getJavaType()
                 << " _hidl_out_"
@@ -663,7 +661,7 @@
             out << "_hidl_reply.writeStatus(android.os.HwParcel.STATUS_SUCCESS);\n";
 
             if (returnsValue) {
-                const TypedVar *returnArg = method->results()[0];
+                const NamedReference<Type>* returnArg = method->results()[0];
 
                 emitJavaReaderWriter(
                         out,
diff --git a/hidl-gen_y.yy b/hidl-gen_y.yy
index 805f671..664cf8a 100644
--- a/hidl-gen_y.yy
+++ b/hidl-gen_y.yy
@@ -296,12 +296,12 @@
     android::TemplatedType *templatedType;
     android::FQName *fqName;
     android::CompoundType *compoundType;
-    android::CompoundField *field;
-    std::vector<android::CompoundField *> *fields;
+    android::NamedReference<android::Type>* field;
+    std::vector<android::NamedReference<android::Type>*>* fields;
     android::EnumValue *enumValue;
     android::ConstantExpression *constantExpression;
     std::vector<android::EnumValue *> *enumValues;
-    android::TypedVar *typedVar;
+    android::NamedReference<android::Type>* typedVar;
     android::TypedVarVector *typedVars;
     android::Method *method;
     android::CompoundType::Style compoundStyle;
@@ -425,6 +425,7 @@
     : const_expr
       {
           $$ = new std::vector<ConstantExpression *>;
+          $1->evaluate();
           $$->push_back($1);
       }
     | '{' annotation_const_expr_values '}' { $$ = $2; }
@@ -434,11 +435,13 @@
     : const_expr
       {
           $$ = new std::vector<ConstantExpression *>;
+          $1->evaluate();
           $$->push_back($1);
       }
     | annotation_const_expr_values ',' const_expr
       {
           $$ = $1;
+          $3->evaluate();
           $$->push_back($3);
       }
     ;
@@ -757,7 +760,7 @@
     ;
 
 const_expr
-    : INTEGER                   { $$ = new ConstantExpression($1); }
+    : INTEGER                   { $$ = new LiteralConstantExpression($1); }
     | fqname
       {
           if(!$1->isValidValueName()) {
@@ -766,6 +769,7 @@
                         << @1 << ".\n";
               YYERROR;
           }
+
           if($1->isIdentifier()) {
               std::string identifier = $1->name();
               LocalIdentifier *iden = (*scope)->lookupIdentifier(identifier);
@@ -779,8 +783,8 @@
                             << " is not an enum value at " << @1 << ".\n";
                   YYERROR;
               }
-              $$ = new ConstantExpression(
-                      *(static_cast<EnumValue *>(iden)->constExpr()), $1->string());
+              $$ = new ReferenceConstantExpression(
+                  Reference<LocalIdentifier>(iden, convertYYLoc(@1)), $1->string());
           } else {
               std::string errorMsg;
               EnumValue* v = ast->lookupEnumValue(*$1, &errorMsg, *scope);
@@ -789,42 +793,42 @@
                   YYERROR;
               }
 
-              // TODO: Support Reference
-              $$ = new ConstantExpression(*(v->constExpr()), $1->string());
+              $$ = new ReferenceConstantExpression(
+                  Reference<LocalIdentifier>(v, convertYYLoc(@1)), $1->string());
           }
       }
     | const_expr '?' const_expr ':' const_expr
       {
-          $$ = new ConstantExpression($1, $3, $5);
+          $$ = new TernaryConstantExpression($1, $3, $5);
       }
-    | const_expr LOGICAL_OR const_expr  { $$ = new ConstantExpression($1, "||", $3); }
-    | const_expr LOGICAL_AND const_expr { $$ = new ConstantExpression($1, "&&", $3); }
-    | const_expr '|' const_expr { $$ = new ConstantExpression($1, "|" , $3); }
-    | const_expr '^' const_expr { $$ = new ConstantExpression($1, "^" , $3); }
-    | const_expr '&' const_expr { $$ = new ConstantExpression($1, "&" , $3); }
-    | const_expr EQUALITY const_expr { $$ = new ConstantExpression($1, "==", $3); }
-    | const_expr NEQ const_expr { $$ = new ConstantExpression($1, "!=", $3); }
-    | const_expr '<' const_expr { $$ = new ConstantExpression($1, "<" , $3); }
-    | const_expr '>' const_expr { $$ = new ConstantExpression($1, ">" , $3); }
-    | const_expr LEQ const_expr { $$ = new ConstantExpression($1, "<=", $3); }
-    | const_expr GEQ const_expr { $$ = new ConstantExpression($1, ">=", $3); }
-    | const_expr LSHIFT const_expr { $$ = new ConstantExpression($1, "<<", $3); }
-    | const_expr RSHIFT const_expr { $$ = new ConstantExpression($1, ">>", $3); }
-    | const_expr '+' const_expr { $$ = new ConstantExpression($1, "+" , $3); }
-    | const_expr '-' const_expr { $$ = new ConstantExpression($1, "-" , $3); }
-    | const_expr '*' const_expr { $$ = new ConstantExpression($1, "*" , $3); }
-    | const_expr '/' const_expr { $$ = new ConstantExpression($1, "/" , $3); }
-    | const_expr '%' const_expr { $$ = new ConstantExpression($1, "%" , $3); }
-    | '+' const_expr %prec UNARY_PLUS  { $$ = new ConstantExpression("+", $2); }
-    | '-' const_expr %prec UNARY_MINUS { $$ = new ConstantExpression("-", $2); }
-    | '!' const_expr { $$ = new ConstantExpression("!", $2); }
-    | '~' const_expr { $$ = new ConstantExpression("~", $2); }
+    | const_expr LOGICAL_OR const_expr  { $$ = new BinaryConstantExpression($1, "||", $3); }
+    | const_expr LOGICAL_AND const_expr { $$ = new BinaryConstantExpression($1, "&&", $3); }
+    | const_expr '|' const_expr { $$ = new BinaryConstantExpression($1, "|" , $3); }
+    | const_expr '^' const_expr { $$ = new BinaryConstantExpression($1, "^" , $3); }
+    | const_expr '&' const_expr { $$ = new BinaryConstantExpression($1, "&" , $3); }
+    | const_expr EQUALITY const_expr { $$ = new BinaryConstantExpression($1, "==", $3); }
+    | const_expr NEQ const_expr { $$ = new BinaryConstantExpression($1, "!=", $3); }
+    | const_expr '<' const_expr { $$ = new BinaryConstantExpression($1, "<" , $3); }
+    | const_expr '>' const_expr { $$ = new BinaryConstantExpression($1, ">" , $3); }
+    | const_expr LEQ const_expr { $$ = new BinaryConstantExpression($1, "<=", $3); }
+    | const_expr GEQ const_expr { $$ = new BinaryConstantExpression($1, ">=", $3); }
+    | const_expr LSHIFT const_expr { $$ = new BinaryConstantExpression($1, "<<", $3); }
+    | const_expr RSHIFT const_expr { $$ = new BinaryConstantExpression($1, ">>", $3); }
+    | const_expr '+' const_expr { $$ = new BinaryConstantExpression($1, "+" , $3); }
+    | const_expr '-' const_expr { $$ = new BinaryConstantExpression($1, "-" , $3); }
+    | const_expr '*' const_expr { $$ = new BinaryConstantExpression($1, "*" , $3); }
+    | const_expr '/' const_expr { $$ = new BinaryConstantExpression($1, "/" , $3); }
+    | const_expr '%' const_expr { $$ = new BinaryConstantExpression($1, "%" , $3); }
+    | '+' const_expr %prec UNARY_PLUS  { $$ = new UnaryConstantExpression("+", $2); }
+    | '-' const_expr %prec UNARY_MINUS { $$ = new UnaryConstantExpression("-", $2); }
+    | '!' const_expr { $$ = new UnaryConstantExpression("!", $2); }
+    | '~' const_expr { $$ = new UnaryConstantExpression("~", $2); }
     | '(' const_expr ')' { $$ = $2; }
     | '(' error ')'
       {
         ast->addSyntaxError();
         // to avoid segfaults
-        $$ = new ConstantExpression(ConstantExpression::Zero(ScalarType::KIND_INT32));
+        $$ = ConstantExpression::Zero(ScalarType::KIND_INT32).release();
       }
     ;
 
@@ -832,11 +836,11 @@
     : error_stmt { $$ = nullptr; }
     | opt_annotations valid_identifier '(' typed_vars ')' require_semicolon
       {
-          $$ = new Method($2, $4, new std::vector<TypedVar *>, false, $1);
+          $$ = new Method($2, $4, new std::vector<NamedReference<Type>*>, false, $1);
       }
     | opt_annotations ONEWAY valid_identifier '(' typed_vars ')' require_semicolon
       {
-          $$ = new Method($3, $5, new std::vector<TypedVar *>, true, $1);
+          $$ = new Method($3, $5, new std::vector<NamedReference<Type>*>, true, $1);
       }
     | opt_annotations valid_identifier '(' typed_vars ')' GENERATES '(' typed_vars ')' require_semicolon
       {
@@ -869,7 +873,7 @@
       }
     ;
 
-typed_var : type valid_identifier { $$ = new TypedVar($2, *$1); }
+typed_var : type valid_identifier { $$ = new NamedReference<Type>($2, *$1); }
     ;
 
 
@@ -915,7 +919,7 @@
     ;
 
 field_declarations
-    : /* empty */ { $$ = new std::vector<CompoundField *>; }
+    : /* empty */ { $$ = new std::vector<NamedReference<Type>*>; }
     | field_declarations field_declaration
       {
           $$ = $1;
@@ -939,7 +943,7 @@
                       << @2 << "\n";
             YYERROR;
         }
-        $$ = new CompoundField($2, *$1);
+        $$ = new NamedReference<Type>($2, *$1);
       }
     | annotated_compound_declaration ';'
       {
@@ -1020,7 +1024,7 @@
 
 enum_value
     : valid_identifier { $$ = new EnumValue($1); }
-    | valid_identifier '=' const_expr { $$ = new EnumValue($1, $3); }
+    | valid_identifier '=' const_expr { $3->evaluate(); $$ = new EnumValue($1, $3); }
     ;
 
 enum_values
@@ -1096,6 +1100,8 @@
 
               YYERROR;
           }
+
+          $3->evaluate();
           if (type.isResolved() && type->isArray()) {
               $$ = new ArrayType(static_cast<ArrayType*>(type.get()), $3);
           } else {
@@ -1105,6 +1111,7 @@
     | array_type '[' const_expr ']'
       {
           $$ = $1;
+          $3->evaluate();
           $$->appendDimension($3);
       }
     ;
@@ -1134,8 +1141,6 @@
 
 %%
 
-#include <android-base/logging.h>
-
 void yy::parser::error(
         const yy::parser::location_type &where,
         const std::string &errstr) {
diff --git a/main.cpp b/main.cpp
index 8c4a760..af53171 100644
--- a/main.cpp
+++ b/main.cpp
@@ -1307,8 +1307,10 @@
 }
 
 // hidl is intentionally leaky. Turn off LeakSanitizer by default.
+// Also disable container overflow detection to prevent false
+// positives (b/64564544)
 extern "C" const char *__asan_default_options() {
-    return "detect_leaks=0";
+    return "detect_leaks=0:detect_container_overflow=0";
 }
 
 int main(int argc, char **argv) {