slang_rs_pragma_handler.cpp revision f52a620440fa62257dfdcf2583f0f9df5b855c76
1#include "slang_rs_context.hpp"
2#include "slang_rs_pragma_handler.hpp"
3
4#include "clang/Lex/Preprocessor.h"         /* for class Preprocessor */
5#include "clang/Lex/Token.h"                /* for class Token */
6#include "clang/Lex/LiteralSupport.h"       /* for class StringLiteralParser */
7#include "clang/Basic/TokenKinds.h"         /* for class Token */
8
9namespace {
10
11using namespace clang;
12using namespace slang;
13
14class RSExportVarPragmaHandler : public RSPragmaHandler {
15private:
16    void handleItem(const std::string& Item) {
17        mContext->addExportVar(Item);
18    }
19
20public:
21    RSExportVarPragmaHandler(llvm::StringRef Name, RSContext* Context) : RSPragmaHandler(Name, Context) { return; }
22
23    void HandlePragma(Preprocessor& PP, Token& FirstToken) {
24        this->handleItemListPragma(PP, FirstToken);
25    }
26};
27
28class RSExportVarAllPragmaHandler : public RSPragmaHandler {
29public:
30    RSExportVarAllPragmaHandler(llvm::StringRef Name, RSContext* Context) : RSPragmaHandler(Name, Context) { return; }
31
32    void HandlePragma(Preprocessor& PP, Token& FirstToken) {
33        this->handleNonParamPragma(PP, FirstToken);
34        mContext->setExportAllNonStaticVars(true);
35    }
36};
37
38class RSExportFuncPragmaHandler : public RSPragmaHandler {
39private:
40    void handleItem(const std::string& Item) {
41        mContext->addExportFunc(Item);
42    }
43
44public:
45    RSExportFuncPragmaHandler(llvm::StringRef Name, RSContext* Context) : RSPragmaHandler(Name, Context) { return; }
46
47    void HandlePragma(Preprocessor& PP, Token& FirstToken) {
48        this->handleItemListPragma(PP, FirstToken);
49    }
50};
51
52class RSExportFuncAllPragmaHandler : public RSPragmaHandler {
53public:
54    RSExportFuncAllPragmaHandler(llvm::StringRef Name, RSContext* Context) : RSPragmaHandler(Name, Context) { return; }
55
56    void HandlePragma(Preprocessor& PP, Token& FirstToken) {
57        this->handleNonParamPragma(PP, FirstToken);
58        mContext->setExportAllNonStaticFuncs(true);
59    }
60};
61
62class RSExportTypePragmaHandler : public RSPragmaHandler {
63private:
64    void handleItem(const std::string& Item) {
65        mContext->addExportType(Item);
66    }
67
68public:
69    RSExportTypePragmaHandler(llvm::StringRef Name, RSContext* Context) : RSPragmaHandler(Name, Context) { return; }
70
71    void HandlePragma(Preprocessor& PP, Token& FirstToken) {
72        this->handleItemListPragma(PP, FirstToken);
73    }
74};
75
76class RSJavaPackageNamePragmaHandler : public RSPragmaHandler {
77public:
78    RSJavaPackageNamePragmaHandler(llvm::StringRef Name, RSContext* Context) : RSPragmaHandler(Name, Context) { return; }
79
80    void HandlePragma(Preprocessor& PP, Token& FirstToken) {
81        /* FIXME: Need to validate the extracted package name from paragma. Currently "all chars" specified in pragma will be treated as package name.
82         *
83         * 18.1 The Grammar of the Java Programming Language, http://java.sun.com/docs/books/jls/third_edition/html/syntax.html#18.1
84         *
85         * CompilationUnit:
86         *         [[Annotations] package QualifiedIdentifier   ;  ] {ImportDeclaration}
87         *         {TypeDeclaration}
88         *
89         * QualifiedIdentifier:
90         *         Identifier { . Identifier }
91         *
92         * Identifier:
93         *         IDENTIFIER
94         *
95         * 3.8 Identifiers, http://java.sun.com/docs/books/jls/third_edition/html/lexical.html#3.8
96         *
97         */
98
99        Token& PragmaToken = FirstToken;
100        std::string PackageName;
101
102        /* Skip first token, "java_package_name" */
103        PP.LexUnexpandedToken(PragmaToken);
104
105        /* Now, the current token must be tok::lpara */
106        if(PragmaToken.isNot(tok::l_paren))
107            return;
108
109        while(PragmaToken.isNot(tok::eom)) {
110            /* Lex package name */
111            PP.LexUnexpandedToken(PragmaToken);
112
113            bool Invalid;
114            std::string Spelling = PP.getSpelling(PragmaToken, &Invalid);
115            if(!Invalid)
116                PackageName.append(Spelling);
117
118            /* Pre-mature end (syntax error will be triggered by preprocessor later) */
119            if(PragmaToken.is(tok::eom) || PragmaToken.is(tok::eof))
120                break;
121            else {
122                /* Next token is ')' (end of paragma) */
123                const Token& NextTok = PP.LookAhead(0);
124                if(NextTok.is(tok::r_paren)) {
125                    mContext->setReflectJavaPackageName(PackageName);
126                    /* Lex until meets tok::eom */
127                    do
128                        PP.LexUnexpandedToken(PragmaToken);
129                    while(PragmaToken.isNot(tok::eom));
130                    break;
131                }
132            }
133        }
134        return;
135    }
136};
137
138class RSReflectLicensePragmaHandler : public RSPragmaHandler {
139private:
140    void handleItem(const std::string& Item) {
141        mContext->setLicenseNote(Item);
142    }
143
144public:
145  RSReflectLicensePragmaHandler(llvm::StringRef Name, RSContext* Context) : RSPragmaHandler(Name, Context) { return; }
146
147    void HandlePragma(Preprocessor& PP, Token& FirstToken) {
148        this->handleOptionalStringLiateralParamPragma(PP, FirstToken);
149    }
150};
151
152}   /* anonymous namespace */
153
154namespace slang {
155
156RSPragmaHandler* RSPragmaHandler::CreatePragmaExportVarHandler(RSContext* Context) {
157    return new RSExportVarPragmaHandler("export_var", Context);
158}
159
160RSPragmaHandler* RSPragmaHandler::CreatePragmaExportVarAllHandler(RSContext* Context) {
161    return new RSExportVarPragmaHandler("export_var_all", Context);
162}
163
164RSPragmaHandler* RSPragmaHandler::CreatePragmaExportFuncHandler(RSContext* Context) {
165    return new RSExportFuncPragmaHandler("export_func", Context);
166}
167
168RSPragmaHandler* RSPragmaHandler::CreatePragmaExportFuncAllHandler(RSContext* Context) {
169    return new RSExportFuncPragmaHandler("export_func_all", Context);
170}
171
172RSPragmaHandler* RSPragmaHandler::CreatePragmaExportTypeHandler(RSContext* Context) {
173    return new RSExportTypePragmaHandler("export_type", Context);
174}
175
176RSPragmaHandler* RSPragmaHandler::CreatePragmaJavaPackageNameHandler(RSContext* Context) {
177    return new RSJavaPackageNamePragmaHandler("java_package_name", Context);
178}
179
180RSPragmaHandler* RSPragmaHandler::CreatePragmaReflectLicenseHandler(RSContext* Context) {
181    return new RSJavaPackageNamePragmaHandler("set_reflect_license", Context);
182}
183
184void RSPragmaHandler::handleItemListPragma(Preprocessor& PP, Token& FirstToken) {
185    Token& PragmaToken = FirstToken;
186
187    /* Skip first token, like "export_var" */
188    PP.LexUnexpandedToken(PragmaToken);
189
190    /* Now, the current token must be tok::lpara */
191    if(PragmaToken.isNot(tok::l_paren))
192        return;
193
194    while(PragmaToken.isNot(tok::eom)) {
195        /* Lex variable name */
196        PP.LexUnexpandedToken(PragmaToken);
197        if(PragmaToken.is(tok::identifier))
198            this->handleItem( PP.getSpelling(PragmaToken) );
199        else
200            break;
201
202        assert(PragmaToken.isNot(tok::eom));
203
204        PP.LexUnexpandedToken(PragmaToken);
205
206        if(PragmaToken.isNot(tok::comma))
207            break;
208    }
209    return;
210}
211
212void RSPragmaHandler::handleNonParamPragma(Preprocessor& PP, Token& FirstToken) {
213    Token& PragmaToken = FirstToken;
214
215    /* Skip first token, like "export_var_all" */
216    PP.LexUnexpandedToken(PragmaToken);
217
218    /* Should be end immediately */
219    if(PragmaToken.isNot(tok::eom))
220        printf("RSPragmaHandler::handleNonParamPragma: expected a tok::eom\n");
221    return;
222}
223
224void RSPragmaHandler::handleOptionalStringLiateralParamPragma(Preprocessor& PP, Token& FirstToken) {
225    Token& PragmaToken = FirstToken;
226
227    /* Skip first token, like "set_reflect_license" */
228    PP.LexUnexpandedToken(PragmaToken);
229
230    /* Now, the current token must be tok::lpara */
231    if(PragmaToken.isNot(tok::l_paren))
232        return;
233
234    /* If not ')', eat the following string literal as the license */
235    PP.LexUnexpandedToken(PragmaToken);
236    if(PragmaToken.isNot(tok::r_paren)) {
237        /* Eat the whole string literal */
238        StringLiteralParser StringLiteral(&PragmaToken, 1, PP);
239        if (StringLiteral.hadError)
240            printf("RSPragmaHandler::handleOptionalStringLiateralParamPragma: illegal string literal\n");
241        else
242            this->handleItem( std::string(StringLiteral.GetString()) );
243
244        /* The current token should be tok::r_para */
245        PP.LexUnexpandedToken(PragmaToken);
246        if (PragmaToken.isNot(tok::r_paren))
247            printf("RSPragmaHandler::handleOptionalStringLiateralParamPragma: expected a ')'\n");
248    } else {
249        /* If no argument, remove the license */
250        this->handleItem( "" );
251    }
252}
253
254}   /* namespace slang */
255