Reflect initializer of an exported variable if any.
(NOTE: record type is unsupported currently)

Change-Id: I26fa50dc38488217420a25bafb07f29f6ab28d28
diff --git a/slang_rs_export_var.cpp b/slang_rs_export_var.cpp
index ece693c..09fe7d4 100644
--- a/slang_rs_export_var.cpp
+++ b/slang_rs_export_var.cpp
@@ -1,7 +1,10 @@
+#include "slang_rs_context.hpp"
 #include "slang_rs_export_var.hpp"
 #include "slang_rs_export_type.hpp" /* for macro GET_CANONICAL_TYPE() */
 
-#include "clang/AST/Type.h"         /* for clang::Type and clang::QualType */
+#include "clang/AST/Type.h"         /* for class clang::Type and clang::QualType */
+
+#include "llvm/ADT/APSInt.h"        /* for class llvm::APSInt */
 
 namespace slang {
 
@@ -10,7 +13,32 @@
     mName(VD->getName().data(), VD->getName().size()),
     mET(ET)
 {
-    return; 
+  const Expr* Initializer = VD->getAnyInitializer();
+  if(Initializer != NULL)
+    switch(ET->getClass()) {
+      case RSExportType::ExportClassPrimitive:
+      case RSExportType::ExportClassVector:
+        Initializer->EvaluateAsAny(mInit, *Context->getASTContext());
+        break;
+
+      case RSExportType::ExportClassPointer:
+        if(Initializer->isNullPointerConstant(*Context->getASTContext(), Expr::NPC_ValueDependentIsNotNull))
+          mInit.Val = APValue(llvm::APSInt(1));
+        else
+          Initializer->EvaluateAsAny(mInit, *Context->getASTContext());
+        break;
+
+      case RSExportType::ExportClassRecord:
+        /* No action */
+        printf("RSExportVar::RSExportVar : Reflection of initializer to variable '%s' (of type '%s') is unsupported currently.\n", mName.c_str(), ET->getName().c_str());
+        break;
+
+      default:
+        assert(false && "Unknown class of type");
+        break;
+    }
+
+  return;
 }
 
 }   /* namespace slang */
diff --git a/slang_rs_export_var.hpp b/slang_rs_export_var.hpp
index 1b1cf0a..e8c73a1 100644
--- a/slang_rs_export_var.hpp
+++ b/slang_rs_export_var.hpp
@@ -4,9 +4,14 @@
 #include "llvm/ADT/StringRef.h"     /* for class llvm::StringRef */
 
 #include "clang/AST/Decl.h"         /* for clang::VarDecl */
+#include "clang/AST/Expr.h"         /* for clang::Expr */
 
 #include <string>
 
+namespace clang {
+    class APValue;
+}
+
 namespace slang {
 
 using namespace clang;
@@ -21,6 +26,8 @@
     std::string mName;
     const RSExportType* mET;
 
+    Expr::EvalResult mInit;
+
     RSExportVar(RSContext* Context, const VarDecl* VD, const RSExportType* ET);
 
 public:
@@ -28,6 +35,8 @@
     inline const RSExportType* getType() const { return mET; }
     inline RSContext* getRSContext() const { return mContext; }
 
+    inline const APValue& getInit() const { return mInit.Val; }
+
 };  /* RSExportVar */
 
 
diff --git a/slang_rs_reflection.cpp b/slang_rs_reflection.cpp
index 5f359dc..7a787d4 100644
--- a/slang_rs_reflection.cpp
+++ b/slang_rs_reflection.cpp
@@ -137,6 +137,19 @@
     return BaseElement[EVT->getNumElement() - 2];
 }
 
+static const char* GetVectorAccessor(int Index) {
+    static const char* VectorAccessorMap[] = {
+        /* 0 */ "x",
+        /* 1 */ "y",
+        /* 2 */ "z",
+        /* 3 */ "w",
+    };
+
+    assert((Index >= 0) && (Index < (sizeof(VectorAccessorMap) / sizeof(const char*))) && "Out-of-bound index to access vector member");
+
+    return VectorAccessorMap[Index];
+}
+
 static const char* GetPackerAPIName(const RSExportPrimitiveType* EPT) {
     static const char* PrimitiveTypePackerAPINameMap[] = {
         "",
@@ -389,10 +402,122 @@
                                                                           "boolean", "isRoot");
     /* Call constructor of super class */
     C.indent() << "super(rs, resources, id, isRoot);" << endl;
+
+    /* If an exported variable has initial value, reflect it */
+
+    for(RSContext::const_export_var_iterator I = mRSContext->export_vars_begin();
+        I != mRSContext->export_vars_end();
+        I++)
+    {
+        const RSExportVar* EV = *I;
+        if(!EV->getInit().isUninit())
+            genInitExportVariable(C, EV->getType(), EV->getName(), EV->getInit());
+    }
+
     C.endFunction();
     return;
 }
 
+void RSReflection::genInitPrimitiveExportVariable(Context& C, const std::string& VarName, const APValue& Val) {
+    assert(!Val.isUninit() && "Not a valid initializer");
+
+    C.indent() << RS_EXPORT_VAR_PREFIX << VarName << " = ";
+    switch(Val.getKind()) {
+        case APValue::Int: C.out() << Val.getInt().getSExtValue(); break;
+        case APValue::Float: C.out() << Val.getFloat().convertToDouble(); break;
+
+        case APValue::ComplexInt:
+        case APValue::ComplexFloat:
+        case APValue::LValue:
+        case APValue::Vector:
+            assert(false && "Primitive type cannot have such kind of initializer");
+        break;
+
+        default:
+            assert(false && "Unknown kind of initializer");
+        break;
+    }
+    C.out() << ";" << endl;
+
+    return;
+}
+
+void RSReflection::genInitExportVariable(Context& C, const RSExportType* ET, const std::string& VarName, const APValue& Val) {
+    assert(!Val.isUninit() && "Not a valid initializer");
+
+    switch(ET->getClass()) {
+        case RSExportType::ExportClassPrimitive:
+            genInitPrimitiveExportVariable(C, VarName, Val);
+        break;
+
+        case RSExportType::ExportClassPointer:
+            if(!Val.isInt() || Val.getInt().getSExtValue() != 0)
+                std::cout << "Initializer which is non-NULL to pointer type variable will be ignored" << endl;
+        break;
+
+        case RSExportType::ExportClassVector:
+        {
+            const RSExportVectorType* EVT = static_cast<const RSExportVectorType*>(ET);
+            switch(Val.getKind()) {
+                case APValue::Int:
+                case APValue::Float:
+                    for(int i=0;i<EVT->getNumElement();i++) {
+                        std::string Name =  VarName + "." + GetVectorAccessor(i);
+                        genInitPrimitiveExportVariable(C, Name, Val);
+                    }
+                break;
+
+                case APValue::Vector:
+                {
+                    C.indent() << RS_EXPORT_VAR_PREFIX << VarName << " = new " << GetVectorTypeName(EVT) << "();" << endl;
+
+                    unsigned NumElements = std::min(static_cast<unsigned>(EVT->getNumElement()), Val.getVectorLength());
+                    for(unsigned i=0;i<NumElements;i++) {
+                        const APValue& ElementVal = Val.getVectorElt(i);
+                        std::string Name =  VarName + "." + GetVectorAccessor(i);
+                        genInitPrimitiveExportVariable(C, Name, ElementVal);
+                    }
+                }
+                break;
+            }
+        }
+        break;
+
+        /* TODO: Resolving initializer of a record type variable is complex. It cannot obtain by just simply evaluating the initializer expression. */
+        case RSExportType::ExportClassRecord:
+        {
+            /*
+            unsigned InitIndex = 0;
+            const RSExportRecordType* ERT = static_cast<const RSExportRecordType*>(ET);
+
+            assert((Val.getKind() == APValue::Vector) && "Unexpected type of initializer for record type variable");
+
+            C.indent() << RS_EXPORT_VAR_PREFIX << VarName << " = new "RS_TYPE_CLASS_NAME_PREFIX << ERT->getName() <<  "."RS_TYPE_ITEM_CLASS_NAME"();" << endl;
+
+            for(RSExportRecordType::const_field_iterator I = ERT->fields_begin();
+                I != ERT->fields_end();
+                I++)
+            {
+                const RSExportRecordType::Field* F = *I;
+                std::string FieldName = VarName + "." + F->getName();
+
+                if(InitIndex > Val.getVectorLength())
+                    break;
+
+                genInitPrimitiveExportVariable(C, FieldName, Val.getVectorElt(InitIndex++));
+            }
+            */
+            assert(false && "Unsupported initializer for record type variable currently");
+        }
+        break;
+
+        default:
+            assert(false && "Unknown class of type");
+        break;
+    }
+    return;
+}
+
 void RSReflection::genExportVariable(Context& C, const RSExportVar* EV) {
     const RSExportType* ET = EV->getType();
 
diff --git a/slang_rs_reflection.hpp b/slang_rs_reflection.hpp
index bd9c8c3..6f43e9c 100644
--- a/slang_rs_reflection.hpp
+++ b/slang_rs_reflection.hpp
@@ -133,6 +133,8 @@
     bool genScriptClass(Context& C, const std::string& ClassName, std::string& ErrorMsg);
     void genScriptClassConstructor(Context& C);
 
+    void genInitPrimitiveExportVariable(Context& C, const std::string& VarName, const APValue& Val);
+    void genInitExportVariable(Context& C, const RSExportType* ET, const std::string& VarName, const APValue& Val);
     void genExportVariable(Context& C, const RSExportVar* EV);
     void genPrimitiveTypeExportVariable(Context& C, const RSExportVar* EV);
     void genPointerTypeExportVariable(Context& C, const RSExportVar* EV);