1 /*
2 * Copyright (c) 2017, Red Hat, Inc.
3 * Copyright (c) 2017, Masatake YAMATO
4 *
5 * This source code is released for free distribution under the terms of the
6 * GNU General Public License version 2 or (at your option) any later version.
7 *
8 * This module contains functions for handling Qt Moc tokens
9 */
10
11 #include "general.h"
12
13 #include "types.h"
14
15 #include "debug.h"
16 #include "cxx_debug.h"
17
18 #include "cxx_scope.h"
19 #include "cxx_parser_internal.h"
20
21 #include "cxx_subparser.h"
22
23 #include "keyword.h"
24 #include "read.h"
25
26 #include <string.h>
27
28
29 typedef enum {
30 K_SLOT,
31 K_SIGNAL,
32 K_PROPERTY,
33 } qtMocKind;
34
35 static kindDefinition QtMocKinds [] = {
36 { true, 's', "slot", "slots" },
37 { true, 'S', "signal", "signals" },
38 { true, 'p', "property", "properties" },
39 };
40
41 enum {
42 KEYWORD_QOBJECT,
43 KEYWORD_SIGNALS,
44 KEYWORD_SLOTS,
45 KEYWORD_PROPERTY,
46 };
47
48 typedef int keywordId; /* to allow KEYWORD_NONE */
49
50 static const keywordTable QtMocKeywordTable[] = {
51 /* keyword keyword ID */
52 { "Q_OBJECT", KEYWORD_QOBJECT },
53 { "Q_SIGNALS", KEYWORD_SIGNALS },
54 { "signals", KEYWORD_SIGNALS },
55 { "Q_SLOTS", KEYWORD_SLOTS },
56 { "slots", KEYWORD_SLOTS },
57 { "Q_PROPERTY", KEYWORD_PROPERTY },
58 };
59
60 enum QtMocMemberMarker
61 {
62 QtMocMemberMarkerNone = 0,
63 QtMocMemberMarkerSlot,
64 QtMocMemberMarkerSignal,
65 };
66
67 struct sQtMocSubparser {
68 struct sCxxSubparser cxx;
69 int iBlockDepth;
70 int iDepthOfQtClass;
71 enum QtMocMemberMarker eMemberMarker;
72 };
73
74 static langType Lang_QtMoc;
75
cxxParserSkipToClosingParenthesisOrEOF(void)76 static bool cxxParserSkipToClosingParenthesisOrEOF(void)
77 {
78 if(cxxTokenTypeIsOneOf(g_cxx.pToken,CXXTokenTypeClosingParenthesis | CXXTokenTypeEOF))
79 return true;
80
81 return cxxParserParseUpToOneOf(CXXTokenTypeClosingParenthesis | CXXTokenTypeEOF,
82 false);
83 }
84
qtMocMakeTagForProperty(CXXToken * pToken,const char * pszType)85 static void qtMocMakeTagForProperty (CXXToken * pToken, const char *pszType)
86 {
87 tagEntryInfo tag;
88
89 initTagEntry(&tag,
90 vStringValue(pToken->pszWord),
91 K_PROPERTY);
92 tag.lineNumber = pToken->iLineNumber;
93 tag.filePosition = pToken->oFilePosition;
94 tag.isFileScope = false;
95
96 if(!cxxScopeIsGlobal())
97 {
98 tag.extensionFields.scopeLangType = getNamedLanguage ("C++", 0); /* ??? */
99 tag.extensionFields.scopeKindIndex = cxxScopeGetKind();
100 tag.extensionFields.scopeName = cxxScopeGetFullName();
101 }
102
103 tag.extensionFields.typeRef[0] = "typename";
104 tag.extensionFields.typeRef[1] = pszType;
105
106 makeTagEntry(&tag);
107 }
108
qtMocParseProperty(void)109 static bool qtMocParseProperty(void)
110 {
111 char *pszPropType;
112
113 CXX_DEBUG_ENTER();
114
115 if(!cxxParserParseNextToken())
116 {
117 CXX_DEBUG_LEAVE_TEXT("EOF in cxxParserParseNextToken");
118 return false;
119 }
120 if (!cxxTokenTypeIs(g_cxx.pToken, CXXTokenTypeOpeningParenthesis))
121 {
122 CXX_DEBUG_LEAVE_TEXT("Found no Opening Parenthesis after Q_PROPERTY");
123 return false;
124 }
125
126 if (!cxxParserParseNextToken())
127 {
128 CXX_DEBUG_LEAVE_TEXT("EOF in cxxParserParseNextToken");
129 return false;
130 }
131 if (!(cxxTokenTypeIs(g_cxx.pToken, CXXTokenTypeIdentifier)
132 || (cxxTokenTypeIs(g_cxx.pToken, CXXTokenTypeKeyword)
133 && cxxKeywordMayBePartOfTypeName (g_cxx.pToken->eKeyword))))
134
135 {
136 CXX_DEBUG_LEAVE_TEXT("Found no identifier after Q_PROPERTY(");
137
138 cxxParserSkipToClosingParenthesisOrEOF ();
139 return false;
140 }
141
142 pszPropType = vStringStrdup (g_cxx.pToken->pszWord);
143 if(!cxxParserParseNextToken())
144 {
145 CXX_DEBUG_LEAVE_TEXT("EOF in cxxParserParseNextToken");
146 eFree (pszPropType);
147 return false;
148 }
149
150 if (!cxxTokenTypeIs(g_cxx.pToken, CXXTokenTypeIdentifier))
151 {
152 CXX_DEBUG_LEAVE_TEXT("Found no identifier after Q_PROPERTY(%s", pszPropType);
153 cxxParserSkipToClosingParenthesisOrEOF ();
154 eFree (pszPropType);
155 return false;
156 }
157
158 qtMocMakeTagForProperty (g_cxx.pToken, pszPropType);
159
160 eFree (pszPropType);
161 cxxParserSkipToClosingParenthesisOrEOF ();
162
163 CXX_DEBUG_LEAVE();
164 return true;
165 }
166
inputStart(subparser * s)167 static void inputStart(subparser *s)
168 {
169 struct sQtMocSubparser *pQtMoc = (struct sQtMocSubparser*)s;
170
171 pQtMoc->iBlockDepth = 0;
172 pQtMoc->iDepthOfQtClass = 0;
173 pQtMoc->eMemberMarker = QtMocMemberMarkerNone;
174 }
175
makeTagEntryNotify(subparser * s,const tagEntryInfo * entry,int corkIndex)176 static void makeTagEntryNotify (subparser *s, const tagEntryInfo *entry, int corkIndex)
177 {
178 struct sQtMocSubparser *pQtMoc = (struct sQtMocSubparser*)s;
179
180 if (pQtMoc->iDepthOfQtClass == 0)
181 return;
182
183 if ((pQtMoc->eMemberMarker != QtMocMemberMarkerNone) &&
184 entry->kindIndex == CXXTagKindPROTOTYPE)
185 {
186 tagEntryInfo parasiteTag = *entry;
187 parasiteTag.langType = getInputLanguage ();
188 parasiteTag.kindIndex = (pQtMoc->eMemberMarker == QtMocMemberMarkerSlot)
189 ? K_SLOT
190 : K_SIGNAL;
191
192 parasiteTag.extensionFields.scopeLangType = entry->langType;
193 makeTagEntry (¶siteTag);
194 }
195 }
196
enterBlockNotify(struct sCxxSubparser * pSubparser)197 static void enterBlockNotify (struct sCxxSubparser *pSubparser)
198 {
199 struct sQtMocSubparser *pQtMoc = (struct sQtMocSubparser *)pSubparser;
200
201 pQtMoc->iBlockDepth++;
202 }
203
leaveBlockNotify(struct sCxxSubparser * pSubparser)204 static void leaveBlockNotify (struct sCxxSubparser *pSubparser)
205 {
206 struct sQtMocSubparser *pQtMoc = (struct sQtMocSubparser *)pSubparser;
207
208 if (pQtMoc->iDepthOfQtClass == pQtMoc->iBlockDepth)
209 pQtMoc->iDepthOfQtClass = 0;
210
211 pQtMoc->iBlockDepth--;
212 }
213
newIdentifierAsHeadOfMemberNotify(struct sCxxSubparser * pSubparser,CXXToken * pToken)214 static bool newIdentifierAsHeadOfMemberNotify (struct sCxxSubparser *pSubparser,
215 CXXToken *pToken)
216 {
217 struct sQtMocSubparser *pQtMoc = (struct sQtMocSubparser *)pSubparser;
218 keywordId keyword = lookupKeyword (vStringValue (pToken->pszWord), Lang_QtMoc);
219
220 if (keyword == KEYWORD_QOBJECT)
221 {
222 if (pQtMoc->iDepthOfQtClass == 0)
223 pQtMoc->iDepthOfQtClass = pQtMoc->iBlockDepth;
224 CXX_DEBUG_PRINT("Found \"Q_OBJECT\" Qt Object Marker in depth: %d",
225 pQtMoc->iDepthOfQtClass);
226 return true;
227 }
228 return false;
229 }
230
unknownIdentifierInClassNotify(struct sCxxSubparser * pSubparser,CXXToken * pToken)231 static bool unknownIdentifierInClassNotify (struct sCxxSubparser *pSubparser,
232 CXXToken *pToken)
233 {
234 struct sQtMocSubparser *pQtMoc = (struct sQtMocSubparser *)pSubparser;
235
236 if (pQtMoc->iDepthOfQtClass == 0)
237 return false;
238
239 keywordId keyword = lookupKeyword (vStringValue (pToken->pszWord), Lang_QtMoc);
240
241 switch (keyword)
242 {
243 case KEYWORD_SIGNALS:
244 CXX_DEBUG_PRINT("Found \"signals\" QtMoc Keyword");
245 pToken->eType = CXXTokenTypeKeyword;
246 pToken->eKeyword = CXXKeywordPUBLIC;
247 cxxParserParseAccessSpecifier();
248 pQtMoc->eMemberMarker = QtMocMemberMarkerSignal;
249 return true;
250 case KEYWORD_SLOTS:
251 CXX_DEBUG_PRINT("Found \"slots\" QtMoc Keyword");
252 pToken->eType = CXXTokenTypeKeyword;
253 g_cxx.pToken->eKeyword = CXXKeywordPUBLIC; /* ??? */
254 cxxParserParseAccessSpecifier();
255 pQtMoc->eMemberMarker = QtMocMemberMarkerSlot;
256 return true;
257 case KEYWORD_PROPERTY:
258 CXX_DEBUG_PRINT("Found \"Q_PROPERTY\" QtMoc Keyword");
259 qtMocParseProperty ();
260 return true;
261 default:
262 break;
263 }
264
265 return false;
266 }
267
parseAccessSpecifierNotify(struct sCxxSubparser * pSubparser)268 static bool parseAccessSpecifierNotify(struct sCxxSubparser *pSubparser)
269 {
270 struct sQtMocSubparser *pQtMoc = (struct sQtMocSubparser *)pSubparser;
271
272 if (pQtMoc->iBlockDepth > 0)
273 {
274 CXX_DEBUG_PRINT("Reset QtMoc member marker state");
275 pQtMoc->eMemberMarker = QtMocMemberMarkerNone;
276 return true;
277 }
278 return false;
279 }
280
foundExtraIdentifierAsAccessSpecifier(struct sCxxSubparser * pSubparser,CXXToken * pToken)281 static void foundExtraIdentifierAsAccessSpecifier(struct sCxxSubparser *pSubparser,
282 CXXToken *pToken)
283 {
284 struct sQtMocSubparser *pQtMoc = (struct sQtMocSubparser *)pSubparser;
285 keywordId keyword = lookupKeyword (vStringValue (pToken->pszWord), Lang_QtMoc);
286
287 if (keyword == KEYWORD_SLOTS)
288 {
289 CXX_DEBUG_PRINT("Found \"slots\" QtMoc Keyword");
290 pQtMoc->eMemberMarker = QtMocMemberMarkerSlot;
291 }
292 }
293
findQtMocTags(void)294 static void findQtMocTags(void)
295 {
296 scheduleRunningBaseparser (0);
297 }
298
initialize(langType lang)299 static void initialize (langType lang)
300 {
301 Lang_QtMoc = lang;
302 }
303
QtMocParser(void)304 extern parserDefinition* QtMocParser (void)
305 {
306 parserDefinition* const def = parserNew("QtMoc");
307
308 static struct sQtMocSubparser qtMocSubparser = {
309 .cxx = {
310 .subparser = {
311 .direction = SUBPARSER_BI_DIRECTION,
312 .inputStart = inputStart,
313 .makeTagEntryNotify = makeTagEntryNotify,
314 },
315 .enterBlockNotify = enterBlockNotify,
316 .leaveBlockNotify = leaveBlockNotify,
317 .newIdentifierAsHeadOfMemberNotify = newIdentifierAsHeadOfMemberNotify,
318 .unknownIdentifierInClassNotify = unknownIdentifierInClassNotify,
319 .parseAccessSpecifierNotify = parseAccessSpecifierNotify,
320 .foundExtraIdentifierAsAccessSpecifier = foundExtraIdentifierAsAccessSpecifier,
321 }
322 /* The rest fields are initialized in inputStart(). */
323 };
324 static parserDependency dependencies [] = {
325 [0] = { DEPTYPE_SUBPARSER, "C++", &qtMocSubparser },
326 };
327
328 def->dependencies = dependencies;
329 def->dependencyCount = ARRAY_SIZE (dependencies);
330
331 def->kindTable = QtMocKinds;
332 def->kindCount = ARRAY_SIZE(QtMocKinds);
333
334 def->keywordTable = QtMocKeywordTable;
335 def->keywordCount = ARRAY_SIZE (QtMocKeywordTable);
336
337 def->parser = findQtMocTags;
338 def->initialize = initialize;
339 def->useCork = CORK_QUEUE;
340
341 return def;
342 }
343