slang_rs_context.cpp revision a6d60672695f1438a63acdbf85eae7f97ce2b50d
1#include "slang_rs_context.h" 2 3#include "llvm/LLVMContext.h" 4#include "llvm/Target/TargetData.h" 5 6#include "clang/Basic/TargetInfo.h" 7#include "clang/Basic/Linkage.h" 8#include "clang/AST/Type.h" 9#include "clang/AST/Decl.h" 10#include "clang/AST/DeclBase.h" 11#include "clang/AST/ASTContext.h" 12#include "clang/Index/ASTLocation.h" 13 14#include "slang.h" 15#include "slang_rs_reflection.h" 16#include "slang_rs_exportable.h" 17#include "slang_rs_export_var.h" 18#include "slang_rs_export_func.h" 19#include "slang_rs_export_type.h" 20#include "slang_rs_pragma_handler.h" 21 22using namespace slang; 23 24RSContext::RSContext(clang::Preprocessor *PP, 25 clang::ASTContext *Ctx, 26 const clang::TargetInfo *Target) 27 : mPP(PP), 28 mCtx(Ctx), 29 mTarget(Target), 30 mTargetData(NULL), 31 mLLVMContext(llvm::getGlobalContext()), 32 mExportAllNonStaticVars(true), 33 mExportAllNonStaticFuncs(false), 34 mLicenseNote(NULL) { 35 // For #pragma rs export_var 36 PP->AddPragmaHandler( 37 "rs", RSPragmaHandler::CreatePragmaExportVarHandler(this)); 38 39 // For #pragma rs export_var_all 40 PP->AddPragmaHandler( 41 "rs", RSPragmaHandler::CreatePragmaExportVarAllHandler(this)); 42 43 // For #pragma rs export_func 44 PP->AddPragmaHandler( 45 "rs", RSPragmaHandler::CreatePragmaExportFuncHandler(this)); 46 47 // For #pragma rs export_func_all 48 PP->AddPragmaHandler( 49 "rs", RSPragmaHandler::CreatePragmaExportFuncAllHandler(this)); 50 51 // For #pragma rs export_type 52 PP->AddPragmaHandler( 53 "rs", RSPragmaHandler::CreatePragmaExportTypeHandler(this)); 54 55 // For #pragma rs java_package_name 56 PP->AddPragmaHandler( 57 "rs", RSPragmaHandler::CreatePragmaJavaPackageNameHandler(this)); 58 59 // For #pragma rs set_reflect_license 60 PP->AddPragmaHandler( 61 "rs", RSPragmaHandler::CreatePragmaReflectLicenseHandler(this)); 62 63 // Prepare target data 64 mTargetData = new llvm::TargetData(Slang::TargetDescription); 65 66 return; 67} 68 69bool RSContext::processExportVar(const clang::VarDecl *VD) { 70 assert(!VD->getName().empty() && "Variable name should not be empty"); 71 72 // TODO(zonr): some check on variable 73 74 RSExportType *ET = RSExportType::CreateFromDecl(this, VD); 75 if (!ET) 76 return false; 77 78 RSExportVar *EV = new RSExportVar(this, VD, ET); 79 if (EV == NULL) 80 return false; 81 else 82 mExportVars.push_back(EV); 83 84 return true; 85} 86 87bool RSContext::processExportFunc(const clang::FunctionDecl *FD) { 88 assert(!FD->getName().empty() && "Function name should not be empty"); 89 90 if (!FD->isThisDeclarationADefinition()) 91 return false; 92 93 if (FD->getStorageClass() != clang::SC_None) { 94 fprintf(stderr, "RSContext::processExportFunc : cannot export extern or " 95 "static function '%s'\n", FD->getName().str().c_str()); 96 return false; 97 } 98 99 RSExportFunc *EF = RSExportFunc::Create(this, FD); 100 if (EF == NULL) 101 return false; 102 else 103 mExportFuncs.push_back(EF); 104 105 return true; 106} 107 108 109bool RSContext::processExportType(const llvm::StringRef &Name) { 110 clang::TranslationUnitDecl *TUDecl = mCtx->getTranslationUnitDecl(); 111 112 assert(TUDecl != NULL && "Translation unit declaration (top-level " 113 "declaration) is null object"); 114 115 const clang::IdentifierInfo *II = mPP->getIdentifierInfo(Name); 116 if (II == NULL) 117 // TODO(zonr): alert identifier @Name mark as an exportable type cannot be 118 // found 119 return false; 120 121 clang::DeclContext::lookup_const_result R = TUDecl->lookup(II); 122 RSExportType *ET = NULL; 123 124 RSExportPointerType::IntegerType = mCtx->IntTy.getTypePtr(); 125 126 for (clang::DeclContext::lookup_const_iterator I = R.first, E = R.second; 127 I != E; 128 I++) { 129 clang::NamedDecl *const ND = *I; 130 const clang::Type *T = NULL; 131 132 switch (ND->getKind()) { 133 case clang::Decl::Typedef: { 134 T = static_cast<const clang::TypedefDecl*>( 135 ND)->getCanonicalDecl()->getUnderlyingType().getTypePtr(); 136 break; 137 } 138 case clang::Decl::Record: { 139 T = static_cast<const clang::RecordDecl*>(ND)->getTypeForDecl(); 140 break; 141 } 142 default: { 143 // unsupported, skip 144 break; 145 } 146 } 147 148 if (T != NULL) 149 ET = RSExportType::Create(this, T); 150 } 151 152 RSExportPointerType::IntegerType = NULL; 153 154 return (ET != NULL); 155} 156 157void RSContext::processExport() { 158 if (mNeedExportVars.empty() && 159 mNeedExportFuncs.empty() && 160 !mExportAllNonStaticVars && !mExportAllNonStaticFuncs) { 161 fprintf(stderr, "note: No reflection because there are no #pragma " 162 "rs export_var(...), #pragma rs export_func(...), " 163 "#pragma rs export_var_all, or #pragma rs " 164 "export_func_all\n"); 165 } 166 167 // Export variable 168 clang::TranslationUnitDecl *TUDecl = mCtx->getTranslationUnitDecl(); 169 for (clang::DeclContext::decl_iterator DI = TUDecl->decls_begin(), 170 DE = TUDecl->decls_end(); 171 DI != TUDecl->decls_end(); 172 DI++) { 173 if (DI->getKind() == clang::Decl::Var) { 174 clang::VarDecl *VD = (clang::VarDecl*) (*DI); 175 if (mExportAllNonStaticVars && 176 (VD->getLinkage() == clang::ExternalLinkage)) { 177 if (!processExportVar(VD)) { 178 fprintf(stderr, "RSContext::processExport : failed to export var " 179 "'%s'\n", VD->getNameAsString().c_str()); 180 } 181 } else { 182 NeedExportVarSet::iterator EI = mNeedExportVars.find(VD->getName()); 183 if (EI != mNeedExportVars.end() && processExportVar(VD)) { 184 mNeedExportVars.erase(EI); 185 } 186 } 187 } else if (DI->getKind() == clang::Decl::Function) { 188 // Export functions 189 clang::FunctionDecl *FD = (clang::FunctionDecl*) (*DI); 190 if (mExportAllNonStaticFuncs && 191 (FD->getLinkage() == clang::ExternalLinkage)) { 192 if (!processExportFunc(FD)) { 193 fprintf(stderr, "RSContext::processExport : failed to export func " 194 "'%s'\n", FD->getNameAsString().c_str()); 195 } 196 } else { 197 NeedExportFuncSet::iterator EI = mNeedExportFuncs.find(FD->getName()); 198 if (EI != mNeedExportFuncs.end() && processExportFunc(FD)) 199 mNeedExportFuncs.erase(EI); 200 } 201 } 202 } 203 204 // Finally, export type forcely set to be exported by user 205 for (NeedExportTypeSet::const_iterator EI = mNeedExportTypes.begin(), 206 EE = mNeedExportTypes.end(); 207 EI != EE; 208 EI++) { 209 if (!processExportType(EI->getKey())) { 210 fprintf(stderr, "RSContext::processExport : failed to export type " 211 "'%s'\n", EI->getKey().str().c_str()); 212 } 213 } 214 215 return; 216} 217 218bool RSContext::insertExportType(const llvm::StringRef &TypeName, 219 RSExportType *ET) { 220 ExportTypeMap::value_type *NewItem = 221 ExportTypeMap::value_type::Create(TypeName.begin(), 222 TypeName.end(), 223 mExportTypes.getAllocator(), 224 ET); 225 226 if (mExportTypes.insert(NewItem)) { 227 return true; 228 } else { 229 free(NewItem); 230 return false; 231 } 232} 233 234bool RSContext::reflectToJava(const char *OutputPackageName, 235 const std::string &InputFileName, 236 const std::string &OutputBCFileName, 237 char realPackageName[], 238 int bSize) { 239 if (realPackageName != NULL) { 240 *realPackageName = 0; 241 } 242 243 if (OutputPackageName == NULL) { 244 if (!mReflectJavaPackageName.empty()) { 245 OutputPackageName = mReflectJavaPackageName.c_str(); 246 } else { 247 // no package name, just return 248 return true; 249 } 250 } 251 252 // Copy back the really applied package name 253 if (realPackageName != NULL) { 254 strncpy(realPackageName, OutputPackageName, bSize - 1); 255 } 256 257 RSReflection *R = new RSReflection(this); 258 bool ret = R->reflect(OutputPackageName, InputFileName, OutputBCFileName); 259 if (!ret) 260 fprintf(stderr, "RSContext::reflectToJava : failed to do reflection " 261 "(%s)\n", R->getLastError()); 262 delete R; 263 return ret; 264} 265 266bool RSContext::reflectToJavaPath(const char *OutputPathName) { 267 if (OutputPathName == NULL) 268 // no path name, just return 269 return true; 270 271 setReflectJavaPathName(std::string(OutputPathName)); 272 return true; 273} 274 275RSContext::~RSContext() { 276 delete mLicenseNote; 277 delete mTargetData; 278 for (ExportableList::iterator I = mExportables.begin(), 279 E = mExportables.end(); 280 I != E; 281 I++) { 282 delete *I; 283 } 284} 285