blob: 7d444959474cbc8e948fe9ba674817b673b74d36 [file] [log] [blame]
Zonr Changc383a502010-10-12 01:52:08 +08001/*
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
zonr6315f762010-10-05 15:35:14 +080017#include "slang_rs_pragma_handler.h"
Shih-wei Liao462aefd2010-06-04 15:32:04 -070018
Stephen Hines3fd0a942011-01-18 12:27:39 -080019#include <sstream>
Stephen Hinese639eb52010-11-08 19:27:20 -080020#include <string>
21
Shih-wei Liao9ef2f782010-10-01 12:31:37 -070022#include "clang/Basic/TokenKinds.h"
Shih-wei Liao462aefd2010-06-04 15:32:04 -070023
Shih-wei Liao9ef2f782010-10-01 12:31:37 -070024#include "clang/Lex/LiteralSupport.h"
25#include "clang/Lex/Preprocessor.h"
26#include "clang/Lex/Token.h"
Shih-wei Liao462aefd2010-06-04 15:32:04 -070027
Stephen Hines6e6578a2011-02-07 18:05:48 -080028#include "slang_assert.h"
zonr6315f762010-10-05 15:35:14 +080029#include "slang_rs_context.h"
30
Stephen Hinese639eb52010-11-08 19:27:20 -080031namespace slang {
Shih-wei Liao462aefd2010-06-04 15:32:04 -070032
Shih-wei Liao9ef2f782010-10-01 12:31:37 -070033namespace { // Anonymous namespace
34
Shih-wei Liao462aefd2010-06-04 15:32:04 -070035class RSExportTypePragmaHandler : public RSPragmaHandler {
Shih-wei Liao9ef2f782010-10-01 12:31:37 -070036 private:
zonr6315f762010-10-05 15:35:14 +080037 void handleItem(const std::string &Item) {
Stephen Hines3fd0a942011-01-18 12:27:39 -080038 mContext->addPragma(this->getName(), Item);
Shih-wei Liao9ef2f782010-10-01 12:31:37 -070039 mContext->addExportType(Item);
40 }
Shih-wei Liao462aefd2010-06-04 15:32:04 -070041
Shih-wei Liao9ef2f782010-10-01 12:31:37 -070042 public:
zonr6315f762010-10-05 15:35:14 +080043 RSExportTypePragmaHandler(llvm::StringRef Name, RSContext *Context)
44 : RSPragmaHandler(Name, Context) { return; }
Shih-wei Liao462aefd2010-06-04 15:32:04 -070045
Shih-wei Liaodf5bcce2011-02-28 18:39:23 -080046 void HandlePragma(clang::Preprocessor &PP,
47 clang::PragmaIntroducerKind Introducer,
48 clang::Token &FirstToken) {
Shih-wei Liao9ef2f782010-10-01 12:31:37 -070049 this->handleItemListPragma(PP, FirstToken);
50 }
Shih-wei Liao462aefd2010-06-04 15:32:04 -070051};
52
Shih-wei Liao537446c2010-06-11 16:05:55 -070053class RSJavaPackageNamePragmaHandler : public RSPragmaHandler {
Shih-wei Liao9ef2f782010-10-01 12:31:37 -070054 public:
zonr6315f762010-10-05 15:35:14 +080055 RSJavaPackageNamePragmaHandler(llvm::StringRef Name, RSContext *Context)
56 : RSPragmaHandler(Name, Context) { return; }
Shih-wei Liao537446c2010-06-11 16:05:55 -070057
Shih-wei Liaodf5bcce2011-02-28 18:39:23 -080058 void HandlePragma(clang::Preprocessor &PP,
59 clang::PragmaIntroducerKind Introducer,
60 clang::Token &FirstToken) {
Stephen Hines35f5b392010-11-22 16:39:16 -080061 // FIXME: Need to validate the extracted package name from pragma.
Shih-wei Liao9ef2f782010-10-01 12:31:37 -070062 // 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 //
Shih-wei Liao537446c2010-06-11 16:05:55 -070082
Shih-wei Liao9ef2f782010-10-01 12:31:37 -070083 clang::Token &PragmaToken = FirstToken;
84 std::string PackageName;
Shih-wei Liao537446c2010-06-11 16:05:55 -070085
Shih-wei Liao9ef2f782010-10-01 12:31:37 -070086 // Skip first token, "java_package_name"
87 PP.LexUnexpandedToken(PragmaToken);
Shih-wei Liao537446c2010-06-11 16:05:55 -070088
Shih-wei Liao9ef2f782010-10-01 12:31:37 -070089 // Now, the current token must be clang::tok::lpara
90 if (PragmaToken.isNot(clang::tok::l_paren))
91 return;
Shih-wei Liao537446c2010-06-11 16:05:55 -070092
Loganbe274822011-02-16 22:02:54 +080093 while (PragmaToken.isNot(clang::tok::eod)) {
Shih-wei Liao9ef2f782010-10-01 12:31:37 -070094 // 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)
Loganbe274822011-02-16 22:02:54 +0800103 if (PragmaToken.is(clang::tok::eod) || PragmaToken.is(clang::tok::eof)) {
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700104 break;
zonr6315f762010-10-05 15:35:14 +0800105 } else {
Stephen Hines96ab06c2011-01-05 15:29:26 -0800106 // Next token is ')' (end of pragma)
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700107 const clang::Token &NextTok = PP.LookAhead(0);
108 if (NextTok.is(clang::tok::r_paren)) {
Stephen Hines3fd0a942011-01-18 12:27:39 -0800109 mContext->addPragma(this->getName(), PackageName);
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700110 mContext->setReflectJavaPackageName(PackageName);
Loganbe274822011-02-16 22:02:54 +0800111 // Lex until meets clang::tok::eod
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700112 do {
Shih-wei Liao537446c2010-06-11 16:05:55 -0700113 PP.LexUnexpandedToken(PragmaToken);
Loganbe274822011-02-16 22:02:54 +0800114 } while (PragmaToken.isNot(clang::tok::eod));
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700115 break;
Shih-wei Liao537446c2010-06-11 16:05:55 -0700116 }
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700117 }
Shih-wei Liao537446c2010-06-11 16:05:55 -0700118 }
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700119 return;
120 }
Shih-wei Liao537446c2010-06-11 16:05:55 -0700121};
122
Victor Hsiehd8a0d182010-07-07 19:22:33 +0800123class RSReflectLicensePragmaHandler : public RSPragmaHandler {
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700124 private:
125 void handleItem(const std::string &Item) {
Stephen Hines3fd0a942011-01-18 12:27:39 -0800126 mContext->addPragma(this->getName(), Item);
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700127 mContext->setLicenseNote(Item);
128 }
Victor Hsiehd8a0d182010-07-07 19:22:33 +0800129
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700130 public:
131 RSReflectLicensePragmaHandler(llvm::StringRef Name, RSContext *Context)
132 : RSPragmaHandler(Name, Context) { return; }
Victor Hsiehd8a0d182010-07-07 19:22:33 +0800133
Shih-wei Liaodf5bcce2011-02-28 18:39:23 -0800134 void HandlePragma(clang::Preprocessor &PP,
135 clang::PragmaIntroducerKind Introducer,
136 clang::Token &FirstToken) {
Stephen Hines9d2c0fa2011-01-05 14:55:18 -0800137 this->handleOptionalStringLiteralParamPragma(PP, FirstToken);
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700138 }
Victor Hsiehd8a0d182010-07-07 19:22:33 +0800139};
140
Stephen Hines96ab06c2011-01-05 15:29:26 -0800141class RSVersionPragmaHandler : public RSPragmaHandler {
142 private:
Stephen Hines7aff4a02011-12-08 18:34:27 -0800143 void handleInt(clang::Preprocessor &PP,
144 clang::Token &Tok,
145 const int v) {
146 if (v != 1) {
147 PP.Diag(Tok,
148 PP.getDiagnostics().getCustomDiagID(
149 clang::DiagnosticsEngine::Error,
150 "pragma for version in source file must be set to 1"));
151 mContext->setVersion(1);
152 return;
153 }
Stephen Hines3fd0a942011-01-18 12:27:39 -0800154 std::stringstream ss;
155 ss << v;
156 mContext->addPragma(this->getName(), ss.str());
Stephen Hines96ab06c2011-01-05 15:29:26 -0800157 mContext->setVersion(v);
158 }
159
160 public:
161 RSVersionPragmaHandler(llvm::StringRef Name, RSContext *Context)
162 : RSPragmaHandler(Name, Context) { return; }
163
Shih-wei Liaodf5bcce2011-02-28 18:39:23 -0800164 void HandlePragma(clang::Preprocessor &PP,
165 clang::PragmaIntroducerKind Introducer,
166 clang::Token &FirstToken) {
Stephen Hines96ab06c2011-01-05 15:29:26 -0800167 this->handleIntegerParamPragma(PP, FirstToken);
168 }
169};
170
Stephen Hinese639eb52010-11-08 19:27:20 -0800171} // namespace
Shih-wei Liao462aefd2010-06-04 15:32:04 -0700172
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700173RSPragmaHandler *
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700174RSPragmaHandler::CreatePragmaExportTypeHandler(RSContext *Context) {
175 return new RSExportTypePragmaHandler("export_type", Context);
Shih-wei Liao462aefd2010-06-04 15:32:04 -0700176}
177
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700178RSPragmaHandler *
179RSPragmaHandler::CreatePragmaJavaPackageNameHandler(RSContext *Context) {
180 return new RSJavaPackageNamePragmaHandler("java_package_name", Context);
Shih-wei Liao537446c2010-06-11 16:05:55 -0700181}
182
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700183RSPragmaHandler *
184RSPragmaHandler::CreatePragmaReflectLicenseHandler(RSContext *Context) {
Stephen Hinesd09df092011-02-03 16:01:12 -0800185 return new RSReflectLicensePragmaHandler("set_reflect_license", Context);
Victor Hsiehd8a0d182010-07-07 19:22:33 +0800186}
187
Stephen Hines96ab06c2011-01-05 15:29:26 -0800188RSPragmaHandler *
189RSPragmaHandler::CreatePragmaVersionHandler(RSContext *Context) {
190 return new RSVersionPragmaHandler("version", Context);
191}
192
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700193void RSPragmaHandler::handleItemListPragma(clang::Preprocessor &PP,
194 clang::Token &FirstToken) {
195 clang::Token &PragmaToken = FirstToken;
Shih-wei Liao462aefd2010-06-04 15:32:04 -0700196
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700197 // Skip first token, like "export_var"
198 PP.LexUnexpandedToken(PragmaToken);
Shih-wei Liao462aefd2010-06-04 15:32:04 -0700199
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700200 // Now, the current token must be clang::tok::lpara
201 if (PragmaToken.isNot(clang::tok::l_paren))
Shih-wei Liao462aefd2010-06-04 15:32:04 -0700202 return;
Shih-wei Liao462aefd2010-06-04 15:32:04 -0700203
Loganbe274822011-02-16 22:02:54 +0800204 while (PragmaToken.isNot(clang::tok::eod)) {
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700205 // Lex variable name
206 PP.LexUnexpandedToken(PragmaToken);
207 if (PragmaToken.is(clang::tok::identifier))
zonr6315f762010-10-05 15:35:14 +0800208 this->handleItem(PP.getSpelling(PragmaToken));
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700209 else
210 break;
Victor Hsiehc6718b32010-06-23 09:29:44 +0800211
Loganbe274822011-02-16 22:02:54 +0800212 slangAssert(PragmaToken.isNot(clang::tok::eod));
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700213
Victor Hsiehc6718b32010-06-23 09:29:44 +0800214 PP.LexUnexpandedToken(PragmaToken);
215
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700216 if (PragmaToken.isNot(clang::tok::comma))
217 break;
218 }
219 return;
220}
221
zonr6315f762010-10-05 15:35:14 +0800222void RSPragmaHandler::handleNonParamPragma(clang::Preprocessor &PP,
223 clang::Token &FirstToken) {
224 clang::Token &PragmaToken = FirstToken;
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700225
226 // Skip first token, like "export_var_all"
227 PP.LexUnexpandedToken(PragmaToken);
228
229 // Should be end immediately
Loganbe274822011-02-16 22:02:54 +0800230 if (PragmaToken.isNot(clang::tok::eod))
Stephen Hines7aff4a02011-12-08 18:34:27 -0800231 if (PragmaToken.isNot(clang::tok::r_paren)) {
232 PP.Diag(PragmaToken,
233 PP.getDiagnostics().getCustomDiagID(
234 clang::DiagnosticsEngine::Error,
235 "expected a ')'"));
236 return;
237 }
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700238 return;
239}
240
Stephen Hines9d2c0fa2011-01-05 14:55:18 -0800241void RSPragmaHandler::handleOptionalStringLiteralParamPragma(
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700242 clang::Preprocessor &PP, clang::Token &FirstToken) {
243 clang::Token &PragmaToken = FirstToken;
244
245 // Skip first token, like "set_reflect_license"
246 PP.LexUnexpandedToken(PragmaToken);
247
248 // Now, the current token must be clang::tok::lpara
249 if (PragmaToken.isNot(clang::tok::l_paren))
Victor Hsiehc6718b32010-06-23 09:29:44 +0800250 return;
Victor Hsiehc6718b32010-06-23 09:29:44 +0800251
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700252 // If not ')', eat the following string literal as the license
253 PP.LexUnexpandedToken(PragmaToken);
254 if (PragmaToken.isNot(clang::tok::r_paren)) {
255 // Eat the whole string literal
256 clang::StringLiteralParser StringLiteral(&PragmaToken, 1, PP);
Stephen Hines7aff4a02011-12-08 18:34:27 -0800257 if (StringLiteral.hadError) {
258 // Diagnostics will be generated automatically
259 return;
Stephen Hinese67239d2012-02-24 15:08:36 -0800260 } else {
zonr6315f762010-10-05 15:35:14 +0800261 this->handleItem(std::string(StringLiteral.GetString()));
Stephen Hines7aff4a02011-12-08 18:34:27 -0800262 }
Victor Hsiehd8a0d182010-07-07 19:22:33 +0800263
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700264 // The current token should be clang::tok::r_para
Victor Hsiehd8a0d182010-07-07 19:22:33 +0800265 PP.LexUnexpandedToken(PragmaToken);
Stephen Hines7aff4a02011-12-08 18:34:27 -0800266 if (PragmaToken.isNot(clang::tok::r_paren)) {
267 PP.Diag(PragmaToken,
268 PP.getDiagnostics().getCustomDiagID(
269 clang::DiagnosticsEngine::Error,
270 "expected a ')'"));
271 return;
272 }
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700273 } else {
274 // If no argument, remove the license
zonr6315f762010-10-05 15:35:14 +0800275 this->handleItem("");
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700276 }
Victor Hsiehd8a0d182010-07-07 19:22:33 +0800277}
Stephen Hinese639eb52010-11-08 19:27:20 -0800278
Stephen Hines96ab06c2011-01-05 15:29:26 -0800279void RSPragmaHandler::handleIntegerParamPragma(
280 clang::Preprocessor &PP, clang::Token &FirstToken) {
281 clang::Token &PragmaToken = FirstToken;
282
283 // Skip first token, like "version"
284 PP.LexUnexpandedToken(PragmaToken);
285
286 // Now, the current token must be clang::tok::lpara
Stephen Hines7aff4a02011-12-08 18:34:27 -0800287 if (PragmaToken.isNot(clang::tok::l_paren)) {
288 // If no argument, set the version to 0
289 this->handleInt(PP, PragmaToken, 0);
Stephen Hines96ab06c2011-01-05 15:29:26 -0800290 return;
Stephen Hines7aff4a02011-12-08 18:34:27 -0800291 }
Stephen Hines96ab06c2011-01-05 15:29:26 -0800292 PP.LexUnexpandedToken(PragmaToken);
293
294 if (PragmaToken.is(clang::tok::numeric_constant)) {
Stephen Hines23c43582013-01-09 20:02:04 -0800295 llvm::SmallString<128> SpellingBuffer;
296 SpellingBuffer.resize(PragmaToken.getLength() + 1);
297 llvm::StringRef TokSpelling = PP.getSpelling(PragmaToken, SpellingBuffer);
298 clang::NumericLiteralParser NumericLiteral(TokSpelling,
Stephen Hines96ab06c2011-01-05 15:29:26 -0800299 PragmaToken.getLocation(), PP);
300 if (NumericLiteral.hadError) {
Stephen Hines7aff4a02011-12-08 18:34:27 -0800301 // Diagnostics will be generated automatically
302 return;
Stephen Hines96ab06c2011-01-05 15:29:26 -0800303 } else {
304 llvm::APInt Val(32, 0);
305 NumericLiteral.GetIntegerValue(Val);
Stephen Hines7aff4a02011-12-08 18:34:27 -0800306 this->handleInt(PP, PragmaToken, static_cast<int>(Val.getSExtValue()));
Stephen Hines96ab06c2011-01-05 15:29:26 -0800307 }
308 PP.LexUnexpandedToken(PragmaToken);
309 } else {
310 // If no argument, set the version to 0
Stephen Hines7aff4a02011-12-08 18:34:27 -0800311 this->handleInt(PP, PragmaToken, 0);
Stephen Hines96ab06c2011-01-05 15:29:26 -0800312 }
313
314 if (PragmaToken.isNot(clang::tok::r_paren)) {
Stephen Hines7aff4a02011-12-08 18:34:27 -0800315 PP.Diag(PragmaToken,
316 PP.getDiagnostics().getCustomDiagID(
317 clang::DiagnosticsEngine::Error,
318 "expected a ')'"));
319 return;
Stephen Hines96ab06c2011-01-05 15:29:26 -0800320 }
321
322 do {
323 PP.LexUnexpandedToken(PragmaToken);
Loganbe274822011-02-16 22:02:54 +0800324 } while (PragmaToken.isNot(clang::tok::eod));
Stephen Hines96ab06c2011-01-05 15:29:26 -0800325}
326
Stephen Hinese639eb52010-11-08 19:27:20 -0800327} // namespace slang