blob: 2d8223206c5787bc04cadc65aaa7b3bab743faa3 [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)
Jean-Luc Brouillet796e7b12014-05-27 11:35:17 -070044 : RSPragmaHandler(Name, Context) { }
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)
Jean-Luc Brouillet796e7b12014-05-27 11:35:17 -070056 : RSPragmaHandler(Name, Context) { }
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 }
Shih-wei Liao537446c2010-06-11 16:05:55 -0700120};
121
Victor Hsiehd8a0d182010-07-07 19:22:33 +0800122class RSReflectLicensePragmaHandler : public RSPragmaHandler {
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700123 private:
124 void handleItem(const std::string &Item) {
Stephen Hines3fd0a942011-01-18 12:27:39 -0800125 mContext->addPragma(this->getName(), Item);
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700126 mContext->setLicenseNote(Item);
127 }
Victor Hsiehd8a0d182010-07-07 19:22:33 +0800128
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700129 public:
130 RSReflectLicensePragmaHandler(llvm::StringRef Name, RSContext *Context)
Jean-Luc Brouillet796e7b12014-05-27 11:35:17 -0700131 : RSPragmaHandler(Name, Context) { }
Victor Hsiehd8a0d182010-07-07 19:22:33 +0800132
Shih-wei Liaodf5bcce2011-02-28 18:39:23 -0800133 void HandlePragma(clang::Preprocessor &PP,
134 clang::PragmaIntroducerKind Introducer,
135 clang::Token &FirstToken) {
Stephen Hines9d2c0fa2011-01-05 14:55:18 -0800136 this->handleOptionalStringLiteralParamPragma(PP, FirstToken);
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700137 }
Victor Hsiehd8a0d182010-07-07 19:22:33 +0800138};
139
Stephen Hines96ab06c2011-01-05 15:29:26 -0800140class RSVersionPragmaHandler : public RSPragmaHandler {
141 private:
Stephen Hines7aff4a02011-12-08 18:34:27 -0800142 void handleInt(clang::Preprocessor &PP,
143 clang::Token &Tok,
144 const int v) {
145 if (v != 1) {
146 PP.Diag(Tok,
147 PP.getDiagnostics().getCustomDiagID(
148 clang::DiagnosticsEngine::Error,
149 "pragma for version in source file must be set to 1"));
150 mContext->setVersion(1);
151 return;
152 }
Stephen Hines3fd0a942011-01-18 12:27:39 -0800153 std::stringstream ss;
154 ss << v;
155 mContext->addPragma(this->getName(), ss.str());
Stephen Hines96ab06c2011-01-05 15:29:26 -0800156 mContext->setVersion(v);
157 }
158
159 public:
160 RSVersionPragmaHandler(llvm::StringRef Name, RSContext *Context)
Jean-Luc Brouillet796e7b12014-05-27 11:35:17 -0700161 : RSPragmaHandler(Name, Context) { }
Stephen Hines96ab06c2011-01-05 15:29:26 -0800162
Shih-wei Liaodf5bcce2011-02-28 18:39:23 -0800163 void HandlePragma(clang::Preprocessor &PP,
164 clang::PragmaIntroducerKind Introducer,
165 clang::Token &FirstToken) {
Stephen Hines96ab06c2011-01-05 15:29:26 -0800166 this->handleIntegerParamPragma(PP, FirstToken);
167 }
168};
169
Jean-Luc Brouillet109e90a2014-07-07 17:36:07 -0700170// Handles the pragmas rs_fp_full, rs_fp_relaxed, and rs_fp_imprecise.
171// There's one instance of this handler for each of the above values.
172// Only getName() differs between the instances.
173class RSPrecisionPragmaHandler : public RSPragmaHandler {
174public:
175 RSPrecisionPragmaHandler(llvm::StringRef Name, RSContext *Context)
176 : RSPragmaHandler(Name, Context) {}
177
178 void HandlePragma(clang::Preprocessor &PP,
179 clang::PragmaIntroducerKind Introducer,
180 clang::Token &Token) {
181 std::string Precision = getName();
182 // We are deprecating rs_fp_imprecise.
183 if (Precision == "rs_fp_imprecise") {
184 PP.Diag(Token, PP.getDiagnostics().getCustomDiagID(
185 clang::DiagnosticsEngine::Warning,
186 "rs_fp_imprecise is deprecated. Assuming "
187 "rs_fp_relaxed instead."));
188 Precision = "rs_fp_relaxed";
189 }
190 // Check if we have already encountered a precision pragma already.
191 std::string PreviousPrecision = mContext->getPrecision();
192 if (!PreviousPrecision.empty()) {
193 // If the previous specified a different value, it's an error.
194 if (PreviousPrecision != Precision) {
195 PP.Diag(Token, PP.getDiagnostics().getCustomDiagID(
196 clang::DiagnosticsEngine::Error,
197 "Multiple float precisions specified. Encountered "
198 "%0 previously."))
199 << PreviousPrecision;
200 }
201 // Otherwise we ignore redundant entries.
202 return;
203 }
204
205 mContext->addPragma(Precision, "");
206 mContext->setPrecision(Precision);
207 }
208};
209
Stephen Hinese639eb52010-11-08 19:27:20 -0800210} // namespace
Shih-wei Liao462aefd2010-06-04 15:32:04 -0700211
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700212void RSPragmaHandler::handleItemListPragma(clang::Preprocessor &PP,
213 clang::Token &FirstToken) {
214 clang::Token &PragmaToken = FirstToken;
Shih-wei Liao462aefd2010-06-04 15:32:04 -0700215
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700216 // Skip first token, like "export_var"
217 PP.LexUnexpandedToken(PragmaToken);
Shih-wei Liao462aefd2010-06-04 15:32:04 -0700218
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700219 // Now, the current token must be clang::tok::lpara
220 if (PragmaToken.isNot(clang::tok::l_paren))
Shih-wei Liao462aefd2010-06-04 15:32:04 -0700221 return;
Shih-wei Liao462aefd2010-06-04 15:32:04 -0700222
Loganbe274822011-02-16 22:02:54 +0800223 while (PragmaToken.isNot(clang::tok::eod)) {
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700224 // Lex variable name
225 PP.LexUnexpandedToken(PragmaToken);
226 if (PragmaToken.is(clang::tok::identifier))
zonr6315f762010-10-05 15:35:14 +0800227 this->handleItem(PP.getSpelling(PragmaToken));
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700228 else
229 break;
Victor Hsiehc6718b32010-06-23 09:29:44 +0800230
Loganbe274822011-02-16 22:02:54 +0800231 slangAssert(PragmaToken.isNot(clang::tok::eod));
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700232
Victor Hsiehc6718b32010-06-23 09:29:44 +0800233 PP.LexUnexpandedToken(PragmaToken);
234
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700235 if (PragmaToken.isNot(clang::tok::comma))
236 break;
237 }
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700238}
239
zonr6315f762010-10-05 15:35:14 +0800240void RSPragmaHandler::handleNonParamPragma(clang::Preprocessor &PP,
241 clang::Token &FirstToken) {
242 clang::Token &PragmaToken = FirstToken;
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700243
244 // Skip first token, like "export_var_all"
245 PP.LexUnexpandedToken(PragmaToken);
246
247 // Should be end immediately
Loganbe274822011-02-16 22:02:54 +0800248 if (PragmaToken.isNot(clang::tok::eod))
Stephen Hines7aff4a02011-12-08 18:34:27 -0800249 if (PragmaToken.isNot(clang::tok::r_paren)) {
250 PP.Diag(PragmaToken,
251 PP.getDiagnostics().getCustomDiagID(
252 clang::DiagnosticsEngine::Error,
253 "expected a ')'"));
254 return;
255 }
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700256}
257
Stephen Hines9d2c0fa2011-01-05 14:55:18 -0800258void RSPragmaHandler::handleOptionalStringLiteralParamPragma(
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700259 clang::Preprocessor &PP, clang::Token &FirstToken) {
260 clang::Token &PragmaToken = FirstToken;
261
262 // Skip first token, like "set_reflect_license"
263 PP.LexUnexpandedToken(PragmaToken);
264
265 // Now, the current token must be clang::tok::lpara
266 if (PragmaToken.isNot(clang::tok::l_paren))
Victor Hsiehc6718b32010-06-23 09:29:44 +0800267 return;
Victor Hsiehc6718b32010-06-23 09:29:44 +0800268
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700269 // If not ')', eat the following string literal as the license
270 PP.LexUnexpandedToken(PragmaToken);
271 if (PragmaToken.isNot(clang::tok::r_paren)) {
272 // Eat the whole string literal
Stephen Hines2eb9a3f2014-07-15 16:50:03 -0700273 clang::StringLiteralParser StringLiteral(PragmaToken, PP);
Stephen Hines7aff4a02011-12-08 18:34:27 -0800274 if (StringLiteral.hadError) {
275 // Diagnostics will be generated automatically
276 return;
Stephen Hinese67239d2012-02-24 15:08:36 -0800277 } else {
zonr6315f762010-10-05 15:35:14 +0800278 this->handleItem(std::string(StringLiteral.GetString()));
Stephen Hines7aff4a02011-12-08 18:34:27 -0800279 }
Victor Hsiehd8a0d182010-07-07 19:22:33 +0800280
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700281 // The current token should be clang::tok::r_para
Victor Hsiehd8a0d182010-07-07 19:22:33 +0800282 PP.LexUnexpandedToken(PragmaToken);
Stephen Hines7aff4a02011-12-08 18:34:27 -0800283 if (PragmaToken.isNot(clang::tok::r_paren)) {
284 PP.Diag(PragmaToken,
285 PP.getDiagnostics().getCustomDiagID(
286 clang::DiagnosticsEngine::Error,
287 "expected a ')'"));
288 return;
289 }
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700290 } else {
291 // If no argument, remove the license
zonr6315f762010-10-05 15:35:14 +0800292 this->handleItem("");
Shih-wei Liao9ef2f782010-10-01 12:31:37 -0700293 }
Victor Hsiehd8a0d182010-07-07 19:22:33 +0800294}
Stephen Hinese639eb52010-11-08 19:27:20 -0800295
Stephen Hines96ab06c2011-01-05 15:29:26 -0800296void RSPragmaHandler::handleIntegerParamPragma(
297 clang::Preprocessor &PP, clang::Token &FirstToken) {
298 clang::Token &PragmaToken = FirstToken;
299
300 // Skip first token, like "version"
301 PP.LexUnexpandedToken(PragmaToken);
302
303 // Now, the current token must be clang::tok::lpara
Stephen Hines7aff4a02011-12-08 18:34:27 -0800304 if (PragmaToken.isNot(clang::tok::l_paren)) {
305 // If no argument, set the version to 0
306 this->handleInt(PP, PragmaToken, 0);
Stephen Hines96ab06c2011-01-05 15:29:26 -0800307 return;
Stephen Hines7aff4a02011-12-08 18:34:27 -0800308 }
Stephen Hines96ab06c2011-01-05 15:29:26 -0800309 PP.LexUnexpandedToken(PragmaToken);
310
311 if (PragmaToken.is(clang::tok::numeric_constant)) {
Stephen Hines23c43582013-01-09 20:02:04 -0800312 llvm::SmallString<128> SpellingBuffer;
313 SpellingBuffer.resize(PragmaToken.getLength() + 1);
314 llvm::StringRef TokSpelling = PP.getSpelling(PragmaToken, SpellingBuffer);
315 clang::NumericLiteralParser NumericLiteral(TokSpelling,
Stephen Hines96ab06c2011-01-05 15:29:26 -0800316 PragmaToken.getLocation(), PP);
317 if (NumericLiteral.hadError) {
Stephen Hines7aff4a02011-12-08 18:34:27 -0800318 // Diagnostics will be generated automatically
319 return;
Stephen Hines96ab06c2011-01-05 15:29:26 -0800320 } else {
321 llvm::APInt Val(32, 0);
322 NumericLiteral.GetIntegerValue(Val);
Stephen Hines7aff4a02011-12-08 18:34:27 -0800323 this->handleInt(PP, PragmaToken, static_cast<int>(Val.getSExtValue()));
Stephen Hines96ab06c2011-01-05 15:29:26 -0800324 }
325 PP.LexUnexpandedToken(PragmaToken);
326 } else {
327 // If no argument, set the version to 0
Stephen Hines7aff4a02011-12-08 18:34:27 -0800328 this->handleInt(PP, PragmaToken, 0);
Stephen Hines96ab06c2011-01-05 15:29:26 -0800329 }
330
331 if (PragmaToken.isNot(clang::tok::r_paren)) {
Stephen Hines7aff4a02011-12-08 18:34:27 -0800332 PP.Diag(PragmaToken,
333 PP.getDiagnostics().getCustomDiagID(
334 clang::DiagnosticsEngine::Error,
335 "expected a ')'"));
336 return;
Stephen Hines96ab06c2011-01-05 15:29:26 -0800337 }
338
339 do {
340 PP.LexUnexpandedToken(PragmaToken);
Loganbe274822011-02-16 22:02:54 +0800341 } while (PragmaToken.isNot(clang::tok::eod));
Stephen Hines96ab06c2011-01-05 15:29:26 -0800342}
343
Jean-Luc Brouillet109e90a2014-07-07 17:36:07 -0700344void AddPragmaHandlers(clang::Preprocessor &PP, RSContext *RsContext) {
345 // For #pragma rs export_type
346 PP.AddPragmaHandler("rs",
347 new RSExportTypePragmaHandler("export_type", RsContext));
348
349 // For #pragma rs java_package_name
350 PP.AddPragmaHandler(
351 "rs", new RSJavaPackageNamePragmaHandler("java_package_name", RsContext));
352
353 // For #pragma rs set_reflect_license
354 PP.AddPragmaHandler(
355 "rs", new RSReflectLicensePragmaHandler("set_reflect_license", RsContext));
356
357 // For #pragma version
358 PP.AddPragmaHandler(new RSVersionPragmaHandler("version", RsContext));
359
360 // For #pragma rs_fp*
361 PP.AddPragmaHandler(new RSPrecisionPragmaHandler("rs_fp_full", RsContext));
362 PP.AddPragmaHandler(new RSPrecisionPragmaHandler("rs_fp_relaxed", RsContext));
363 PP.AddPragmaHandler(new RSPrecisionPragmaHandler("rs_fp_imprecise", RsContext));
364}
365
366
Stephen Hinese639eb52010-11-08 19:27:20 -0800367} // namespace slang