Merge pull request #3948 from techee/warning_fix2
[geany-mirror.git] / ctags / parsers / cxx / cxx_parser_module.c
blobe035b93513de2974b0f3391106075d16c89e67b0
1 /*
2 * Copyright (c) 2024, Masatake YAMATO
4 * This source code is released for free distribution under the terms of the
5 * GNU General Public License version 2 or (at your option) any later version.
7 * This module contains functions for parsing and scanning C++ source files
9 * Reference:
10 * - https://en.cppreference.com/w/cpp/language/modules
13 #include "cxx_parser.h"
14 #include "cxx_parser_internal.h"
16 #include "cxx_debug.h"
17 #include "cxx_keyword.h"
18 #include "cxx_token.h"
19 #include "cxx_token_chain.h"
20 #include "cxx_scope.h"
22 #include "../cpreprocessor.h"
24 #include "parse.h"
25 #include "vstring.h"
26 #include "read.h"
27 #include "trashbox.h"
29 static CXXToken * pCurrentModuleToken;
31 static void cxxParserSetCurrentModuleToken(CXXToken * pMod)
33 if (pCurrentModuleToken)
34 cxxTokenDestroy(pCurrentModuleToken);
35 pCurrentModuleToken = pMod;
38 void cxxParserDestroyCurrentModuleToken(void)
40 cxxParserSetCurrentModuleToken(NULL);
44 static CXXToken * cxxTokenModuleTokenCreate(CXXToken *pBegin, CXXToken *pEnd)
46 CXXToken * pRet = cxxTokenCopy(pBegin);
48 if (pBegin != pEnd)
50 vString * pszRest = cxxTokenChainJoinRange(pBegin->pNext, pEnd, "",
51 CXXTokenChainJoinNoTrailingSpaces);
52 vStringCat(pRet->pszWord, pszRest);
53 vStringDelete(pszRest);
56 return pRet;
59 bool cxxParserParseModule(void)
61 CXX_DEBUG_ENTER();
63 unsigned int uProperties = 0;
65 if(cxxTagFieldEnabled(CXXTagFieldProperties))
67 if(g_cxx.uKeywordState & CXXParserKeywordStateSeenExport)
68 uProperties |= CXXTagPropertyExport;
71 cxxParserNewStatement();
73 if(!cxxParserParseUpToOneOf(
74 CXXTokenTypeSemicolon | CXXTokenTypeEOF,
75 false
78 CXX_DEBUG_LEAVE_TEXT("Failed to parse up to the next ;");
79 return false;
82 CXXToken * pFirst = cxxTokenChainFirst(g_cxx.pTokenChain);
83 if (cxxTokenTypeIsOneOf(pFirst, CXXTokenTypeSemicolon | CXXTokenTypeEOF))
85 CXXToken * pMod = cxxTokenCreateAnonymousIdentifier(CXXTagCPPKindMODULE, "__gmod_");
86 tagEntryInfo * tag = cxxTagBegin(CXXTagCPPKindMODULE,pMod);
87 if (tag)
88 cxxTagCommit(NULL);
89 cxxTokenDestroy(pMod);
91 else if (cxxTokenTypeIs(pFirst, CXXTokenTypeSingleColon)
92 && pFirst->pNext && cxxTokenIsKeyword(pFirst->pNext, CXXKeywordPRIVATE))
94 CXXToken * pPart = pFirst->pNext;
95 if (pCurrentModuleToken)
97 CXXToken *pMod = cxxTokenCopy(pCurrentModuleToken);
98 cxxScopePush(pMod, CXXScopeTypeModule, CXXScopeAccessUnknown);
101 tagEntryInfo * tag = cxxTagBegin(CXXTagCPPKindPARTITION,pPart);
102 if (tag)
103 cxxTagCommit(NULL);
104 /* export is never set to the private partition. */
106 if (pCurrentModuleToken)
107 cxxScopePop();
109 else if (cxxTokenTypeIs(pFirst, CXXTokenTypeIdentifier))
111 CXXToken * pModBegin = pFirst;
112 CXXToken * pSep = cxxTokenChainNextTokenOfType(pModBegin,
113 CXXTokenTypeSingleColon
114 | CXXTokenTypeSemicolon
115 | CXXTokenTypeEOF);
116 bool bHasPart = (cxxTokenTypeIs(pSep, CXXTokenTypeSingleColon)
117 && pSep->pNext && cxxTokenTypeIs(pSep->pNext, CXXTokenTypeIdentifier)
118 && g_cxx.pToken->pPrev && g_cxx.pToken->pPrev != pSep);
120 CXXToken * pMod = NULL;
122 pMod = cxxTokenModuleTokenCreate(pModBegin, pSep->pPrev);
123 tagEntryInfo * tag = cxxRefTagBegin(CXXTagCPPKindMODULE,
124 bHasPart? CXXTagMODULERolePartOwner: ROLE_DEFINITION_INDEX,
125 pMod);
126 if (tag)
128 vString * pszProperties = (!bHasPart && uProperties) ? cxxTagSetProperties(uProperties) : NULL;
130 cxxTagCommit(NULL);
131 cxxParserSetCurrentModuleToken(cxxTokenCopy(pMod));
132 cxxScopePush(pMod, CXXScopeTypeModule, CXXScopeAccessUnknown);
133 vStringDelete(pszProperties); /* NULL is acceptable. */
135 else
137 cxxParserSetCurrentModuleToken(pMod);
138 pMod = NULL;
142 if (pMod && bHasPart)
144 CXXToken * pPart = cxxTokenModuleTokenCreate(pSep->pNext, g_cxx.pToken->pPrev);
146 tagEntryInfo * tag = cxxTagBegin(CXXTagCPPKindPARTITION,pPart);
147 if (tag)
149 vString * pszProperties = uProperties ? cxxTagSetProperties(uProperties) : NULL;
151 cxxTagCommit(NULL);
152 vStringDelete(pszProperties); /* NULL is acceptable */
154 cxxTokenDestroy(pPart);
157 if (pMod)
158 cxxScopePop();
161 cxxTokenChainClear(g_cxx.pTokenChain);
162 CXX_DEBUG_LEAVE();
163 return true;
166 bool cxxParserParseImport(void)
168 CXX_DEBUG_ENTER();
170 unsigned int uProperties = 0;
172 if(cxxTagFieldEnabled(CXXTagFieldProperties))
174 if(g_cxx.uKeywordState & CXXParserKeywordStateSeenExport)
175 uProperties |= CXXTagPropertyExport;
178 cxxParserNewStatement();
180 if(!cxxParserParseUpToOneOf(
181 CXXTokenTypeSemicolon | CXXTokenTypeEOF,
182 false
185 CXX_DEBUG_LEAVE_TEXT("Failed to parse up to the next ;");
186 return false;
189 CXXToken *pFirst = cxxTokenChainFirst(g_cxx.pTokenChain);
190 if (cxxTokenTypeIs(pFirst, CXXTokenTypeSmallerThanSign))
192 if (pFirst->pNext == NULL
193 || cxxTokenTypeIsOneOf(pFirst->pNext, CXXTokenTypeGreaterThanSign
194 | CXXTokenTypeSemicolon
195 | CXXTokenTypeEOF))
197 cxxTokenChainClear(g_cxx.pTokenChain);
198 CXX_DEBUG_LEAVE_TEXT("Cannot find > on the chain");
199 return true;
202 CXXToken * pHeaderBegin = pFirst->pNext;
203 CXXToken * pSep = cxxTokenChainNextTokenOfType(pHeaderBegin,
204 CXXTokenTypeGreaterThanSign
205 | CXXTokenTypeSemicolon
206 | CXXTokenTypeEOF);
207 CXX_DEBUG_ASSERT(pSep,"Cannot find the end of header file");
208 CXX_DEBUG_ASSERT(pSep != pHeaderBegin, "Unexpected empty header file");
210 CXXToken * pHeader = cxxTokenModuleTokenCreate(pHeaderBegin, pSep->pPrev);
211 tagEntryInfo * tag = cxxRefTagBegin(CXXTagKindINCLUDE,CR_HEADER_SYSTEM,pHeader);
212 if (tag)
214 assignRole(tag, CXXR_HEADER_IMPORTED);
215 if (uProperties & CXXTagPropertyExport)
216 assignRole(tag, CXXR_HEADER_EXPORTED);
217 cxxTagCommit(NULL);
219 cxxTokenDestroy(pHeader);
221 else if (cxxTokenTypeIs(pFirst, CXXTokenTypeStringConstant))
223 const vString *pHName = cppGetLastCharOrStringContents();
224 if (!pHName || vStringIsEmpty(pHName))
226 cxxTokenChainClear(g_cxx.pTokenChain);
227 CXX_DEBUG_LEAVE_TEXT("Empty header name");
228 return true;
231 vStringCopy(pFirst->pszWord, pHName);
232 CXXToken *pHeader = pFirst;
234 tagEntryInfo * tag = cxxRefTagBegin(CXXTagKindINCLUDE,CR_HEADER_LOCAL,pHeader);
235 if (tag)
237 assignRole(tag, CXXR_HEADER_IMPORTED);
238 if (uProperties & CXXTagPropertyExport)
239 assignRole(tag, CXXR_HEADER_EXPORTED);
240 cxxTagCommit(NULL);
243 else if (cxxTokenTypeIs(pFirst, CXXTokenTypeSingleColon))
245 CXXToken * pPartBegin = pFirst->pNext;
247 if (pPartBegin == NULL
248 || pPartBegin == g_cxx.pToken
249 || cxxTokenTypeIsOneOf(pPartBegin, CXXTokenTypeSemicolon
250 | CXXTokenTypeEOF))
252 cxxTokenChainClear(g_cxx.pTokenChain);
253 CXX_DEBUG_LEAVE_TEXT("Empty partition name");
254 return true;
257 CXXToken * pPart = cxxTokenModuleTokenCreate(pPartBegin, g_cxx.pToken->pPrev);
258 if (pCurrentModuleToken)
260 CXXToken *pMod = cxxTokenCopy(pCurrentModuleToken);
261 cxxScopePush(pMod, CXXScopeTypeModule, CXXScopeAccessUnknown);
264 tagEntryInfo * tag = cxxRefTagBegin(CXXTagCPPKindPARTITION,CXXTagPARTITIONRoleImported,pPart);
265 if (tag)
267 vString * pszProperties = uProperties ? cxxTagSetProperties(uProperties) : NULL;
268 cxxTagCommit(NULL);
269 vStringDelete(pszProperties); /* NULL is acceptable. */
271 cxxTokenDestroy(pPart);
273 if (pCurrentModuleToken)
274 cxxScopePop();
276 else if (cxxTokenTypeIsOneOf(pFirst, CXXTokenTypeIdentifier))
278 CXXToken *pModBegin = pFirst;
279 CXXToken * pSep = cxxTokenChainNextTokenOfType(pModBegin,
280 CXXTokenTypeSingleColon
281 | CXXTokenTypeSemicolon
282 | CXXTokenTypeEOF);
283 bool bHasPart = (cxxTokenTypeIs(pSep, CXXTokenTypeSingleColon)
284 && pSep->pNext && cxxTokenTypeIs(pSep->pNext, CXXTokenTypeIdentifier)
285 && g_cxx.pToken->pPrev && g_cxx.pToken->pPrev != pSep);
287 CXXToken * pMod = NULL;
289 pMod = cxxTokenModuleTokenCreate(pModBegin, pSep->pPrev);
290 tagEntryInfo * tag = cxxRefTagBegin(CXXTagCPPKindMODULE,
291 bHasPart? CXXTagMODULERolePartOwner: CXXTagMODULERoleImported,
292 pMod);
293 if (tag)
295 vString * pszProperties = (!bHasPart && uProperties) ? cxxTagSetProperties(uProperties) : NULL;
297 cxxTagCommit(NULL);
298 cxxScopePush(pMod, CXXScopeTypeModule, CXXScopeAccessUnknown);
299 vStringDelete(pszProperties); /* NULL is acceptable. */
301 else
303 cxxTokenDestroy(pMod);
304 pMod = NULL;
308 if (pMod && bHasPart)
310 CXXToken * pPart = cxxTokenModuleTokenCreate(pSep->pNext, g_cxx.pToken->pPrev);
312 tagEntryInfo * tag = cxxRefTagBegin(CXXTagCPPKindPARTITION,
313 CXXTagPARTITIONRoleImported, pPart);
314 if (tag)
316 vString * pszProperties = uProperties ? cxxTagSetProperties(uProperties) : NULL;
318 cxxTagCommit(NULL);
319 vStringDelete(pszProperties); /* NULL is acceptable */
321 cxxTokenDestroy(pPart);
324 if (pMod)
325 cxxScopePop();
328 cxxTokenChainClear(g_cxx.pTokenChain);
329 CXX_DEBUG_LEAVE();
330 return true;