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