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