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