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
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"
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
);
50 vString
* pszRest
= cxxTokenChainJoinRange(pBegin
->pNext
, pEnd
, "",
51 CXXTokenChainJoinNoTrailingSpaces
);
52 vStringCat(pRet
->pszWord
, pszRest
);
53 vStringDelete(pszRest
);
59 bool cxxParserParseModule(void)
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
,
78 CXX_DEBUG_LEAVE_TEXT("Failed to parse up to the next ;");
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
);
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
);
104 /* export is never set to the private partition. */
106 if (pCurrentModuleToken
)
109 else if (cxxTokenTypeIs(pFirst
, CXXTokenTypeIdentifier
))
111 CXXToken
* pModBegin
= pFirst
;
112 CXXToken
* pSep
= cxxTokenChainNextTokenOfType(pModBegin
,
113 CXXTokenTypeSingleColon
114 | CXXTokenTypeSemicolon
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
,
128 vString
* pszProperties
= (!bHasPart
&& uProperties
) ? cxxTagSetProperties(uProperties
) : NULL
;
131 cxxParserSetCurrentModuleToken(cxxTokenCopy(pMod
));
132 cxxScopePush(pMod
, CXXScopeTypeModule
, CXXScopeAccessUnknown
);
133 vStringDelete(pszProperties
); /* NULL is acceptable. */
137 cxxParserSetCurrentModuleToken(pMod
);
142 if (pMod
&& bHasPart
)
144 CXXToken
* pPart
= cxxTokenModuleTokenCreate(pSep
->pNext
, g_cxx
.pToken
->pPrev
);
146 tagEntryInfo
* tag
= cxxTagBegin(CXXTagCPPKindPARTITION
,pPart
);
149 vString
* pszProperties
= uProperties
? cxxTagSetProperties(uProperties
) : NULL
;
152 vStringDelete(pszProperties
); /* NULL is acceptable */
154 cxxTokenDestroy(pPart
);
161 cxxTokenChainClear(g_cxx
.pTokenChain
);
166 bool cxxParserParseImport(void)
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
,
185 CXX_DEBUG_LEAVE_TEXT("Failed to parse up to the next ;");
189 CXXToken
*pFirst
= cxxTokenChainFirst(g_cxx
.pTokenChain
);
190 if (cxxTokenTypeIs(pFirst
, CXXTokenTypeSmallerThanSign
))
192 if (pFirst
->pNext
== NULL
193 || cxxTokenTypeIsOneOf(pFirst
->pNext
, CXXTokenTypeGreaterThanSign
194 | CXXTokenTypeSemicolon
197 cxxTokenChainClear(g_cxx
.pTokenChain
);
198 CXX_DEBUG_LEAVE_TEXT("Cannot find > on the chain");
202 CXXToken
* pHeaderBegin
= pFirst
->pNext
;
203 CXXToken
* pSep
= cxxTokenChainNextTokenOfType(pHeaderBegin
,
204 CXXTokenTypeGreaterThanSign
205 | CXXTokenTypeSemicolon
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
);
214 assignRole(tag
, CXXR_HEADER_IMPORTED
);
215 if (uProperties
& CXXTagPropertyExport
)
216 assignRole(tag
, CXXR_HEADER_EXPORTED
);
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");
231 vStringCopy(pFirst
->pszWord
, pHName
);
232 CXXToken
*pHeader
= pFirst
;
234 tagEntryInfo
* tag
= cxxRefTagBegin(CXXTagKindINCLUDE
,CR_HEADER_LOCAL
,pHeader
);
237 assignRole(tag
, CXXR_HEADER_IMPORTED
);
238 if (uProperties
& CXXTagPropertyExport
)
239 assignRole(tag
, CXXR_HEADER_EXPORTED
);
243 else if (cxxTokenTypeIs(pFirst
, CXXTokenTypeSingleColon
))
245 CXXToken
* pPartBegin
= pFirst
->pNext
;
247 if (pPartBegin
== NULL
248 || pPartBegin
== g_cxx
.pToken
249 || cxxTokenTypeIsOneOf(pPartBegin
, CXXTokenTypeSemicolon
252 cxxTokenChainClear(g_cxx
.pTokenChain
);
253 CXX_DEBUG_LEAVE_TEXT("Empty partition name");
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
);
267 vString
* pszProperties
= uProperties
? cxxTagSetProperties(uProperties
) : NULL
;
269 vStringDelete(pszProperties
); /* NULL is acceptable. */
271 cxxTokenDestroy(pPart
);
273 if (pCurrentModuleToken
)
276 else if (cxxTokenTypeIsOneOf(pFirst
, CXXTokenTypeIdentifier
))
278 CXXToken
*pModBegin
= pFirst
;
279 CXXToken
* pSep
= cxxTokenChainNextTokenOfType(pModBegin
,
280 CXXTokenTypeSingleColon
281 | CXXTokenTypeSemicolon
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
,
295 vString
* pszProperties
= (!bHasPart
&& uProperties
) ? cxxTagSetProperties(uProperties
) : NULL
;
298 cxxScopePush(pMod
, CXXScopeTypeModule
, CXXScopeAccessUnknown
);
299 vStringDelete(pszProperties
); /* NULL is acceptable. */
303 cxxTokenDestroy(pMod
);
308 if (pMod
&& bHasPart
)
310 CXXToken
* pPart
= cxxTokenModuleTokenCreate(pSep
->pNext
, g_cxx
.pToken
->pPrev
);
312 tagEntryInfo
* tag
= cxxRefTagBegin(CXXTagCPPKindPARTITION
,
313 CXXTagPARTITIONRoleImported
, pPart
);
316 vString
* pszProperties
= uProperties
? cxxTagSetProperties(uProperties
) : NULL
;
319 vStringDelete(pszProperties
); /* NULL is acceptable */
321 cxxTokenDestroy(pPart
);
328 cxxTokenChainClear(g_cxx
.pTokenChain
);