slang_rs_pragma_handler.cpp revision 35f5b39f0490953f1fe13ef803b43e3ced9a01d9
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 RSExportTypePragmaHandler : public RSPragmaHandler {
34 private:
35  void handleItem(const std::string &Item) {
36    mContext->addExportType(Item);
37  }
38
39 public:
40  RSExportTypePragmaHandler(llvm::StringRef Name, RSContext *Context)
41      : RSPragmaHandler(Name, Context) { return; }
42
43  void HandlePragma(clang::Preprocessor &PP, clang::Token &FirstToken) {
44    this->handleItemListPragma(PP, FirstToken);
45  }
46};
47
48class RSJavaPackageNamePragmaHandler : public RSPragmaHandler {
49 public:
50  RSJavaPackageNamePragmaHandler(llvm::StringRef Name, RSContext *Context)
51      : RSPragmaHandler(Name, Context) { return; }
52
53  void HandlePragma(clang::Preprocessor &PP, clang::Token &FirstToken) {
54    // FIXME: Need to validate the extracted package name from pragma.
55    // Currently "all chars" specified in pragma will be treated as package
56    // name.
57    //
58    // 18.1 The Grammar of the Java Programming Language
59    // (http://java.sun.com/docs/books/jls/third_edition/html/syntax.html#18.1)
60    //
61    // CompilationUnit:
62    //     [[Annotations] package QualifiedIdentifier   ;  ] {ImportDeclaration}
63    //     {TypeDeclaration}
64    //
65    // QualifiedIdentifier:
66    //     Identifier { . Identifier }
67    //
68    // Identifier:
69    //     IDENTIFIER
70    //
71    // 3.8 Identifiers
72    // (http://java.sun.com/docs/books/jls/third_edition/html/lexical.html#3.8)
73    //
74    //
75
76    clang::Token &PragmaToken = FirstToken;
77    std::string PackageName;
78
79    // Skip first token, "java_package_name"
80    PP.LexUnexpandedToken(PragmaToken);
81
82    // Now, the current token must be clang::tok::lpara
83    if (PragmaToken.isNot(clang::tok::l_paren))
84      return;
85
86    while (PragmaToken.isNot(clang::tok::eom)) {
87      // Lex package name
88      PP.LexUnexpandedToken(PragmaToken);
89
90      bool Invalid;
91      std::string Spelling = PP.getSpelling(PragmaToken, &Invalid);
92      if (!Invalid)
93        PackageName.append(Spelling);
94
95      // Pre-mature end (syntax error will be triggered by preprocessor later)
96      if (PragmaToken.is(clang::tok::eom) || PragmaToken.is(clang::tok::eof)) {
97        break;
98      } else {
99        // Next token is ')' (end of paragma)
100        const clang::Token &NextTok = PP.LookAhead(0);
101        if (NextTok.is(clang::tok::r_paren)) {
102          mContext->setReflectJavaPackageName(PackageName);
103          // Lex until meets clang::tok::eom
104          do {
105            PP.LexUnexpandedToken(PragmaToken);
106          } while (PragmaToken.isNot(clang::tok::eom));
107          break;
108        }
109      }
110    }
111    return;
112  }
113};
114
115class RSReflectLicensePragmaHandler : public RSPragmaHandler {
116 private:
117  void handleItem(const std::string &Item) {
118    mContext->setLicenseNote(Item);
119  }
120
121 public:
122  RSReflectLicensePragmaHandler(llvm::StringRef Name, RSContext *Context)
123      : RSPragmaHandler(Name, Context) { return; }
124
125  void HandlePragma(clang::Preprocessor &PP, clang::Token &FirstToken) {
126    this->handleOptionalStringLiateralParamPragma(PP, FirstToken);
127  }
128};
129
130}  // namespace
131
132RSPragmaHandler *
133RSPragmaHandler::CreatePragmaExportTypeHandler(RSContext *Context) {
134  return new RSExportTypePragmaHandler("export_type", Context);
135}
136
137RSPragmaHandler *
138RSPragmaHandler::CreatePragmaJavaPackageNameHandler(RSContext *Context) {
139  return new RSJavaPackageNamePragmaHandler("java_package_name", Context);
140}
141
142RSPragmaHandler *
143RSPragmaHandler::CreatePragmaReflectLicenseHandler(RSContext *Context) {
144  return new RSJavaPackageNamePragmaHandler("set_reflect_license", Context);
145}
146
147void RSPragmaHandler::handleItemListPragma(clang::Preprocessor &PP,
148                                           clang::Token &FirstToken) {
149  clang::Token &PragmaToken = FirstToken;
150
151  // Skip first token, like "export_var"
152  PP.LexUnexpandedToken(PragmaToken);
153
154  // Now, the current token must be clang::tok::lpara
155  if (PragmaToken.isNot(clang::tok::l_paren))
156    return;
157
158  while (PragmaToken.isNot(clang::tok::eom)) {
159    // Lex variable name
160    PP.LexUnexpandedToken(PragmaToken);
161    if (PragmaToken.is(clang::tok::identifier))
162      this->handleItem(PP.getSpelling(PragmaToken));
163    else
164      break;
165
166    assert(PragmaToken.isNot(clang::tok::eom));
167
168    PP.LexUnexpandedToken(PragmaToken);
169
170    if (PragmaToken.isNot(clang::tok::comma))
171      break;
172  }
173  return;
174}
175
176void RSPragmaHandler::handleNonParamPragma(clang::Preprocessor &PP,
177                                           clang::Token &FirstToken) {
178  clang::Token &PragmaToken = FirstToken;
179
180  // Skip first token, like "export_var_all"
181  PP.LexUnexpandedToken(PragmaToken);
182
183  // Should be end immediately
184  if (PragmaToken.isNot(clang::tok::eom))
185    fprintf(stderr, "RSPragmaHandler::handleNonParamPragma: "
186                    "expected a clang::tok::eom\n");
187  return;
188}
189
190void RSPragmaHandler::handleOptionalStringLiateralParamPragma(
191    clang::Preprocessor &PP, clang::Token &FirstToken) {
192  clang::Token &PragmaToken = FirstToken;
193
194  // Skip first token, like "set_reflect_license"
195  PP.LexUnexpandedToken(PragmaToken);
196
197  // Now, the current token must be clang::tok::lpara
198  if (PragmaToken.isNot(clang::tok::l_paren))
199    return;
200
201  // If not ')', eat the following string literal as the license
202  PP.LexUnexpandedToken(PragmaToken);
203  if (PragmaToken.isNot(clang::tok::r_paren)) {
204    // Eat the whole string literal
205    clang::StringLiteralParser StringLiteral(&PragmaToken, 1, PP);
206    if (StringLiteral.hadError)
207      fprintf(stderr, "RSPragmaHandler::handleOptionalStringLiateralParamPragma"
208                      ": illegal string literal\n");
209    else
210      this->handleItem(std::string(StringLiteral.GetString()));
211
212    // The current token should be clang::tok::r_para
213    PP.LexUnexpandedToken(PragmaToken);
214    if (PragmaToken.isNot(clang::tok::r_paren))
215      fprintf(stderr, "RSPragmaHandler::handleOptionalStringLiateralParamPragma"
216                      ": expected a ')'\n");
217  } else {
218    // If no argument, remove the license
219    this->handleItem("");
220  }
221}
222
223}  // namespace slang
224