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);