slang_rs_pragma_handler.cpp revision e639eb5caa2c386b4a60659a4929e8a6141a2cbe
1/* 2 * Copyright 2010, The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "slang_rs_pragma_handler.h" 18 19#include <string> 20 21#include "clang/Basic/TokenKinds.h" 22 23#include "clang/Lex/LiteralSupport.h" 24#include "clang/Lex/Preprocessor.h" 25#include "clang/Lex/Token.h" 26 27#include "slang_rs_context.h" 28 29namespace slang { 30 31namespace { // Anonymous namespace 32 33class RSExportVarPragmaHandler : public RSPragmaHandler { 34 private: 35 void handleItem(const std::string &Item) { 36 mContext->addExportVar(Item); 37 } 38 39 public: 40 RSExportVarPragmaHandler(llvm::StringRef Name, RSContext *Context) 41 : RSPragmaHandler(Name, Context) { 42 return; 43 } 44 45 void HandlePragma(clang::Preprocessor &PP, clang::Token &FirstToken) { 46 this->handleItemListPragma(PP, FirstToken); 47 } 48}; 49 50class RSExportVarAllPragmaHandler : public RSPragmaHandler { 51 public: 52 RSExportVarAllPragmaHandler(llvm::StringRef Name, RSContext *Context) 53 : RSPragmaHandler(Name, Context) { return; } 54 55 void HandlePragma(clang::Preprocessor &PP, clang::Token &FirstToken) { 56 this->handleNonParamPragma(PP, FirstToken); 57 mContext->setExportAllNonStaticVars(true); 58 } 59}; 60 61class RSExportFuncPragmaHandler : public RSPragmaHandler { 62 private: 63 void handleItem(const std::string &Item) { 64 mContext->addExportFunc(Item); 65 } 66 67 public: 68 RSExportFuncPragmaHandler(llvm::StringRef Name, 69 RSContext *Context) 70 : RSPragmaHandler(Name, Context) { return; } 71 72 void HandlePragma(clang::Preprocessor &PP, clang::Token &FirstToken) { 73 this->handleItemListPragma(PP, FirstToken); 74 } 75}; 76 77class RSExportFuncAllPragmaHandler : public RSPragmaHandler { 78 public: 79 RSExportFuncAllPragmaHandler(llvm::StringRef Name, RSContext *Context) 80 : RSPragmaHandler(Name, Context) { return; } 81 82 void HandlePragma(clang::Preprocessor &PP, clang::Token &FirstToken) { 83 this->handleNonParamPragma(PP, FirstToken); 84 mContext->setExportAllNonStaticFuncs(true); 85 } 86}; 87 88class RSExportTypePragmaHandler : public RSPragmaHandler { 89 private: 90 void handleItem(const std::string &Item) { 91 mContext->addExportType(Item); 92 } 93 94 public: 95 RSExportTypePragmaHandler(llvm::StringRef Name, RSContext *Context) 96 : RSPragmaHandler(Name, Context) { return; } 97 98 void HandlePragma(clang::Preprocessor &PP, clang::Token &FirstToken) { 99 this->handleItemListPragma(PP, FirstToken); 100 } 101}; 102 103class RSJavaPackageNamePragmaHandler : public RSPragmaHandler { 104 public: 105 RSJavaPackageNamePragmaHandler(llvm::StringRef Name, RSContext *Context) 106 : RSPragmaHandler(Name, Context) { return; } 107 108 void HandlePragma(clang::Preprocessor &PP, clang::Token &FirstToken) { 109 // FIXME: Need to validate the extracted package name from paragma. 110 // Currently "all chars" specified in pragma will be treated as package 111 // name. 112 // 113 // 18.1 The Grammar of the Java Programming Language 114 // (http://java.sun.com/docs/books/jls/third_edition/html/syntax.html#18.1) 115 // 116 // CompilationUnit: 117 // [[Annotations] package QualifiedIdentifier ; ] {ImportDeclaration} 118 // {TypeDeclaration} 119 // 120 // QualifiedIdentifier: 121 // Identifier { . Identifier } 122 // 123 // Identifier: 124 // IDENTIFIER 125 // 126 // 3.8 Identifiers 127 // (http://java.sun.com/docs/books/jls/third_edition/html/lexical.html#3.8) 128 // 129 // 130 131 clang::Token &PragmaToken = FirstToken; 132 std::string PackageName; 133 134 // Skip first token, "java_package_name" 135 PP.LexUnexpandedToken(PragmaToken); 136 137 // Now, the current token must be clang::tok::lpara 138 if (PragmaToken.isNot(clang::tok::l_paren)) 139 return; 140 141 while (PragmaToken.isNot(clang::tok::eom)) { 142 // Lex package name 143 PP.LexUnexpandedToken(PragmaToken); 144 145 bool Invalid; 146 std::string Spelling = PP.getSpelling(PragmaToken, &Invalid); 147 if (!Invalid) 148 PackageName.append(Spelling); 149 150 // Pre-mature end (syntax error will be triggered by preprocessor later) 151 if (PragmaToken.is(clang::tok::eom) || PragmaToken.is(clang::tok::eof)) { 152 break; 153 } else { 154 // Next token is ')' (end of paragma) 155 const clang::Token &NextTok = PP.LookAhead(0); 156 if (NextTok.is(clang::tok::r_paren)) { 157 mContext->setReflectJavaPackageName(PackageName); 158 // Lex until meets clang::tok::eom 159 do { 160 PP.LexUnexpandedToken(PragmaToken); 161 } while (PragmaToken.isNot(clang::tok::eom)); 162 break; 163 } 164 } 165 } 166 return; 167 } 168}; 169 170class RSReflectLicensePragmaHandler : public RSPragmaHandler { 171 private: 172 void handleItem(const std::string &Item) { 173 mContext->setLicenseNote(Item); 174 } 175 176 public: 177 RSReflectLicensePragmaHandler(llvm::StringRef Name, RSContext *Context) 178 : RSPragmaHandler(Name, Context) { return; } 179 180 void HandlePragma(clang::Preprocessor &PP, clang::Token &FirstToken) { 181 this->handleOptionalStringLiateralParamPragma(PP, FirstToken); 182 } 183}; 184 185} // namespace 186 187RSPragmaHandler * 188RSPragmaHandler::CreatePragmaExportVarHandler(RSContext *Context) { 189 return new RSExportVarPragmaHandler("export_var", Context); 190} 191 192RSPragmaHandler * 193RSPragmaHandler::CreatePragmaExportVarAllHandler(RSContext *Context) { 194 return new RSExportVarPragmaHandler("export_var_all", Context); 195} 196 197RSPragmaHandler * 198RSPragmaHandler::CreatePragmaExportFuncHandler(RSContext *Context) { 199 return new RSExportFuncPragmaHandler("export_func", Context); 200} 201 202RSPragmaHandler * 203RSPragmaHandler::CreatePragmaExportFuncAllHandler(RSContext *Context) { 204 return new RSExportFuncPragmaHandler("export_func_all", Context); 205} 206 207RSPragmaHandler * 208RSPragmaHandler::CreatePragmaExportTypeHandler(RSContext *Context) { 209 return new RSExportTypePragmaHandler("export_type", Context); 210} 211 212RSPragmaHandler * 213RSPragmaHandler::CreatePragmaJavaPackageNameHandler(RSContext *Context) { 214 return new RSJavaPackageNamePragmaHandler("java_package_name", Context); 215} 216 217RSPragmaHandler * 218RSPragmaHandler::CreatePragmaReflectLicenseHandler(RSContext *Context) { 219 return new RSJavaPackageNamePragmaHandler("set_reflect_license", Context); 220} 221 222void RSPragmaHandler::handleItemListPragma(clang::Preprocessor &PP, 223 clang::Token &FirstToken) { 224 clang::Token &PragmaToken = FirstToken; 225 226 // Skip first token, like "export_var" 227 PP.LexUnexpandedToken(PragmaToken); 228 229 // Now, the current token must be clang::tok::lpara 230 if (PragmaToken.isNot(clang::tok::l_paren)) 231 return; 232 233 while (PragmaToken.isNot(clang::tok::eom)) { 234 // Lex variable name 235 PP.LexUnexpandedToken(PragmaToken); 236 if (PragmaToken.is(clang::tok::identifier)) 237 this->handleItem(PP.getSpelling(PragmaToken)); 238 else 239 break; 240 241 assert(PragmaToken.isNot(clang::tok::eom)); 242 243 PP.LexUnexpandedToken(PragmaToken); 244 245 if (PragmaToken.isNot(clang::tok::comma)) 246 break; 247 } 248 return; 249} 250 251void RSPragmaHandler::handleNonParamPragma(clang::Preprocessor &PP, 252 clang::Token &FirstToken) { 253 clang::Token &PragmaToken = FirstToken; 254 255 // Skip first token, like "export_var_all" 256 PP.LexUnexpandedToken(PragmaToken); 257 258 // Should be end immediately 259 if (PragmaToken.isNot(clang::tok::eom)) 260 fprintf(stderr, "RSPragmaHandler::handleNonParamPragma: " 261 "expected a clang::tok::eom\n"); 262 return; 263} 264 265void RSPragmaHandler::handleOptionalStringLiateralParamPragma( 266 clang::Preprocessor &PP, clang::Token &FirstToken) { 267 clang::Token &PragmaToken = FirstToken; 268 269 // Skip first token, like "set_reflect_license" 270 PP.LexUnexpandedToken(PragmaToken); 271 272 // Now, the current token must be clang::tok::lpara 273 if (PragmaToken.isNot(clang::tok::l_paren)) 274 return; 275 276 // If not ')', eat the following string literal as the license 277 PP.LexUnexpandedToken(PragmaToken); 278 if (PragmaToken.isNot(clang::tok::r_paren)) { 279 // Eat the whole string literal 280 clang::StringLiteralParser StringLiteral(&PragmaToken, 1, PP); 281 if (StringLiteral.hadError) 282 fprintf(stderr, "RSPragmaHandler::handleOptionalStringLiateralParamPragma" 283 ": illegal string literal\n"); 284 else 285 this->handleItem(std::string(StringLiteral.GetString())); 286 287 // The current token should be clang::tok::r_para 288 PP.LexUnexpandedToken(PragmaToken); 289 if (PragmaToken.isNot(clang::tok::r_paren)) 290 fprintf(stderr, "RSPragmaHandler::handleOptionalStringLiateralParamPragma" 291 ": expected a ')'\n"); 292 } else { 293 // If no argument, remove the license 294 this->handleItem(""); 295 } 296} 297 298} // namespace slang 299