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