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 <sstream> 20#include <string> 21 22#include "clang/Basic/TokenKinds.h" 23 24#include "clang/Lex/LiteralSupport.h" 25#include "clang/Lex/Preprocessor.h" 26#include "clang/Lex/Token.h" 27 28#include "slang_assert.h" 29#include "slang_rs_context.h" 30 31namespace slang { 32 33namespace { // Anonymous namespace 34 35class RSExportTypePragmaHandler : public RSPragmaHandler { 36 private: 37 void handleItem(const std::string &Item) { 38 mContext->addPragma(this->getName(), Item); 39 mContext->addExportType(Item); 40 } 41 42 public: 43 RSExportTypePragmaHandler(llvm::StringRef Name, RSContext *Context) 44 : RSPragmaHandler(Name, Context) { return; } 45 46 void HandlePragma(clang::Preprocessor &PP, 47 clang::PragmaIntroducerKind Introducer, 48 clang::Token &FirstToken) { 49 this->handleItemListPragma(PP, FirstToken); 50 } 51}; 52 53class RSJavaPackageNamePragmaHandler : public RSPragmaHandler { 54 public: 55 RSJavaPackageNamePragmaHandler(llvm::StringRef Name, RSContext *Context) 56 : RSPragmaHandler(Name, Context) { return; } 57 58 void HandlePragma(clang::Preprocessor &PP, 59 clang::PragmaIntroducerKind Introducer, 60 clang::Token &FirstToken) { 61 // FIXME: Need to validate the extracted package name from pragma. 62 // Currently "all chars" specified in pragma will be treated as package 63 // name. 64 // 65 // 18.1 The Grammar of the Java Programming Language 66 // (http://java.sun.com/docs/books/jls/third_edition/html/syntax.html#18.1) 67 // 68 // CompilationUnit: 69 // [[Annotations] package QualifiedIdentifier ; ] {ImportDeclaration} 70 // {TypeDeclaration} 71 // 72 // QualifiedIdentifier: 73 // Identifier { . Identifier } 74 // 75 // Identifier: 76 // IDENTIFIER 77 // 78 // 3.8 Identifiers 79 // (http://java.sun.com/docs/books/jls/third_edition/html/lexical.html#3.8) 80 // 81 // 82 83 clang::Token &PragmaToken = FirstToken; 84 std::string PackageName; 85 86 // Skip first token, "java_package_name" 87 PP.LexUnexpandedToken(PragmaToken); 88 89 // Now, the current token must be clang::tok::lpara 90 if (PragmaToken.isNot(clang::tok::l_paren)) 91 return; 92 93 while (PragmaToken.isNot(clang::tok::eod)) { 94 // Lex package name 95 PP.LexUnexpandedToken(PragmaToken); 96 97 bool Invalid; 98 std::string Spelling = PP.getSpelling(PragmaToken, &Invalid); 99 if (!Invalid) 100 PackageName.append(Spelling); 101 102 // Pre-mature end (syntax error will be triggered by preprocessor later) 103 if (PragmaToken.is(clang::tok::eod) || PragmaToken.is(clang::tok::eof)) { 104 break; 105 } else { 106 // Next token is ')' (end of pragma) 107 const clang::Token &NextTok = PP.LookAhead(0); 108 if (NextTok.is(clang::tok::r_paren)) { 109 mContext->addPragma(this->getName(), PackageName); 110 mContext->setReflectJavaPackageName(PackageName); 111 // Lex until meets clang::tok::eod 112 do { 113 PP.LexUnexpandedToken(PragmaToken); 114 } while (PragmaToken.isNot(clang::tok::eod)); 115 break; 116 } 117 } 118 } 119 return; 120 } 121}; 122 123class RSReflectLicensePragmaHandler : public RSPragmaHandler { 124 private: 125 void handleItem(const std::string &Item) { 126 mContext->addPragma(this->getName(), Item); 127 mContext->setLicenseNote(Item); 128 } 129 130 public: 131 RSReflectLicensePragmaHandler(llvm::StringRef Name, RSContext *Context) 132 : RSPragmaHandler(Name, Context) { return; } 133 134 void HandlePragma(clang::Preprocessor &PP, 135 clang::PragmaIntroducerKind Introducer, 136 clang::Token &FirstToken) { 137 this->handleOptionalStringLiteralParamPragma(PP, FirstToken); 138 } 139}; 140 141class RSVersionPragmaHandler : public RSPragmaHandler { 142 private: 143 void handleInt(const int v) { 144 std::stringstream ss; 145 ss << v; 146 mContext->addPragma(this->getName(), ss.str()); 147 mContext->setVersion(v); 148 } 149 150 public: 151 RSVersionPragmaHandler(llvm::StringRef Name, RSContext *Context) 152 : RSPragmaHandler(Name, Context) { return; } 153 154 void HandlePragma(clang::Preprocessor &PP, 155 clang::PragmaIntroducerKind Introducer, 156 clang::Token &FirstToken) { 157 this->handleIntegerParamPragma(PP, FirstToken); 158 } 159}; 160 161} // namespace 162 163RSPragmaHandler * 164RSPragmaHandler::CreatePragmaExportTypeHandler(RSContext *Context) { 165 return new RSExportTypePragmaHandler("export_type", Context); 166} 167 168RSPragmaHandler * 169RSPragmaHandler::CreatePragmaJavaPackageNameHandler(RSContext *Context) { 170 return new RSJavaPackageNamePragmaHandler("java_package_name", Context); 171} 172 173RSPragmaHandler * 174RSPragmaHandler::CreatePragmaReflectLicenseHandler(RSContext *Context) { 175 return new RSReflectLicensePragmaHandler("set_reflect_license", Context); 176} 177 178RSPragmaHandler * 179RSPragmaHandler::CreatePragmaVersionHandler(RSContext *Context) { 180 return new RSVersionPragmaHandler("version", Context); 181} 182 183void RSPragmaHandler::handleItemListPragma(clang::Preprocessor &PP, 184 clang::Token &FirstToken) { 185 clang::Token &PragmaToken = FirstToken; 186 187 // Skip first token, like "export_var" 188 PP.LexUnexpandedToken(PragmaToken); 189 190 // Now, the current token must be clang::tok::lpara 191 if (PragmaToken.isNot(clang::tok::l_paren)) 192 return; 193 194 while (PragmaToken.isNot(clang::tok::eod)) { 195 // Lex variable name 196 PP.LexUnexpandedToken(PragmaToken); 197 if (PragmaToken.is(clang::tok::identifier)) 198 this->handleItem(PP.getSpelling(PragmaToken)); 199 else 200 break; 201 202 slangAssert(PragmaToken.isNot(clang::tok::eod)); 203 204 PP.LexUnexpandedToken(PragmaToken); 205 206 if (PragmaToken.isNot(clang::tok::comma)) 207 break; 208 } 209 return; 210} 211 212void RSPragmaHandler::handleNonParamPragma(clang::Preprocessor &PP, 213 clang::Token &FirstToken) { 214 clang::Token &PragmaToken = FirstToken; 215 216 // Skip first token, like "export_var_all" 217 PP.LexUnexpandedToken(PragmaToken); 218 219 // Should be end immediately 220 if (PragmaToken.isNot(clang::tok::eod)) 221 fprintf(stderr, "RSPragmaHandler::handleNonParamPragma: " 222 "expected a clang::tok::eod\n"); 223 return; 224} 225 226void RSPragmaHandler::handleOptionalStringLiteralParamPragma( 227 clang::Preprocessor &PP, clang::Token &FirstToken) { 228 clang::Token &PragmaToken = FirstToken; 229 230 // Skip first token, like "set_reflect_license" 231 PP.LexUnexpandedToken(PragmaToken); 232 233 // Now, the current token must be clang::tok::lpara 234 if (PragmaToken.isNot(clang::tok::l_paren)) 235 return; 236 237 // If not ')', eat the following string literal as the license 238 PP.LexUnexpandedToken(PragmaToken); 239 if (PragmaToken.isNot(clang::tok::r_paren)) { 240 // Eat the whole string literal 241 clang::StringLiteralParser StringLiteral(&PragmaToken, 1, PP); 242 if (StringLiteral.hadError) 243 fprintf(stderr, "RSPragmaHandler::handleOptionalStringLiteralParamPragma" 244 ": illegal string literal\n"); 245 else 246 this->handleItem(std::string(StringLiteral.GetString())); 247 248 // The current token should be clang::tok::r_para 249 PP.LexUnexpandedToken(PragmaToken); 250 if (PragmaToken.isNot(clang::tok::r_paren)) 251 fprintf(stderr, "RSPragmaHandler::handleOptionalStringLiteralParamPragma" 252 ": expected a ')'\n"); 253 } else { 254 // If no argument, remove the license 255 this->handleItem(""); 256 } 257} 258 259void RSPragmaHandler::handleIntegerParamPragma( 260 clang::Preprocessor &PP, clang::Token &FirstToken) { 261 clang::Token &PragmaToken = FirstToken; 262 263 // Skip first token, like "version" 264 PP.LexUnexpandedToken(PragmaToken); 265 266 // Now, the current token must be clang::tok::lpara 267 if (PragmaToken.isNot(clang::tok::l_paren)) 268 return; 269 PP.LexUnexpandedToken(PragmaToken); 270 271 if (PragmaToken.is(clang::tok::numeric_constant)) { 272 clang::NumericLiteralParser NumericLiteral(PragmaToken.getLiteralData(), 273 PragmaToken.getLiteralData() + PragmaToken.getLength(), 274 PragmaToken.getLocation(), PP); 275 if (NumericLiteral.hadError) { 276 fprintf(stderr, "RSPragmaHandler::handleIntegerParamPragma" 277 ": illegal numeric literal\n"); 278 } else { 279 llvm::APInt Val(32, 0); 280 NumericLiteral.GetIntegerValue(Val); 281 this->handleInt(static_cast<int>(Val.getSExtValue())); 282 } 283 PP.LexUnexpandedToken(PragmaToken); 284 } else { 285 // If no argument, set the version to 0 286 this->handleInt(0); 287 } 288 289 if (PragmaToken.isNot(clang::tok::r_paren)) { 290 fprintf(stderr, "RSPragmaHandler::handleIntegerParamPragma" 291 ": expected a ')'\n"); 292 } 293 294 do { 295 PP.LexUnexpandedToken(PragmaToken); 296 } while (PragmaToken.isNot(clang::tok::eod)); 297} 298 299} // namespace slang 300