xref: /Universal-ctags/parsers/cxx/cxx_scope.c (revision 80edb4d1e055c8a1a936d4e78bc36f777ae471b1)
1 /*
2 *   Copyright (c) 2016, Szymon Tomasz Stefanek
3 *
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.
6 *
7 *   This module contains functions for parsing and scanning C++ source files
8 */
9 
10 #include "cxx_scope.h"
11 
12 #include "vstring.h"
13 #include "debug.h"
14 
15 #include "cxx_tag.h"
16 #include "cxx_debug.h"
17 #include "cxx_token_chain.h"
18 
19 #ifdef CXX_DO_DEBUGGING
20 #include "cxx_parser_internal.h"
21 #endif
22 
23 // The tokens defining current scope
24 static CXXTokenChain * g_pScope = NULL;
25 static vString * g_szScopeName = NULL;
26 static bool g_bScopeNameDirty = true;
27 
cxxScopeInit(void)28 void cxxScopeInit(void)
29 {
30 	g_pScope = cxxTokenChainCreate();
31 }
32 
cxxScopeDone(void)33 void cxxScopeDone(void)
34 {
35 	cxxTokenChainDestroy(g_pScope);
36 	if(g_szScopeName)
37 	{
38 		vStringDelete(g_szScopeName);
39 		g_szScopeName = NULL;
40 	}
41 }
42 
cxxScopeClear(void)43 void cxxScopeClear(void)
44 {
45 	if(g_pScope)
46 		cxxTokenChainClear(g_pScope);
47 	if(g_szScopeName)
48 	{
49 		vStringDelete(g_szScopeName);
50 		g_szScopeName = NULL;
51 	}
52 }
53 
cxxScopeIsGlobal(void)54 bool cxxScopeIsGlobal(void)
55 {
56 	return (g_pScope->iCount < 1);
57 }
58 
cxxScopeGetType(void)59 enum CXXScopeType cxxScopeGetType(void)
60 {
61 	if(g_pScope->iCount < 1)
62 		return CXXScopeTypeNamespace;
63 	return (enum CXXScopeType)g_pScope->pTail->uInternalScopeType;
64 }
65 
cxxScopeGetVariableKind(void)66 unsigned int cxxScopeGetVariableKind(void)
67 {
68 	switch(cxxScopeGetType())
69 	{
70 		case CXXScopeTypeClass:
71 		case CXXScopeTypeUnion:
72 		case CXXScopeTypeStruct:
73 			return CXXTagKindMEMBER;
74 		break;
75 		case CXXScopeTypeFunction:
76 			return CXXTagKindLOCAL;
77 		break;
78 		//case CXXScopeTypePrototype:
79 		//case CXXScopeTypeNamespace:
80 		//case CXXScopeTypeEnum:
81 		default:
82 			// fall down
83 		break;
84 	}
85 	return CXXTagKindVARIABLE;
86 }
87 
88 
cxxScopeGetKind(void)89 unsigned int cxxScopeGetKind(void)
90 {
91 	CXX_DEBUG_ASSERT(g_pScope->iCount >= 0,"Must not be called in global scope");
92 
93 	switch(g_pScope->pTail->uInternalScopeType)
94 	{
95 		case CXXScopeTypeNamespace:
96 			CXX_DEBUG_ASSERT(cxxParserCurrentLanguageIsCPP(),"C++ only");
97 			return CXXTagCPPKindNAMESPACE;
98 		case CXXScopeTypeClass:
99 			CXX_DEBUG_ASSERT(cxxParserCurrentLanguageIsCPP(),"C++ only");
100 			return CXXTagCPPKindCLASS;
101 		case CXXScopeTypeEnum:
102 			return CXXTagKindENUM;
103 		case CXXScopeTypeFunction:
104 			return CXXTagKindFUNCTION;
105 		case CXXScopeTypePrototype:
106 			return CXXTagKindPROTOTYPE;
107 		case CXXScopeTypeStruct:
108 			return CXXTagKindSTRUCT;
109 		case CXXScopeTypeUnion:
110 			return CXXTagKindUNION;
111 		case CXXScopeTypeVariable:
112 			return CXXTagKindVARIABLE;
113 		case CXXScopeTypeTypedef:
114 			return CXXTagKindTYPEDEF;
115 		default:
116 			CXX_DEBUG_ASSERT(false,"Unhandled scope type!");
117 			break;
118 	}
119 
120 	return CXXTagKindFUNCTION;
121 }
122 
123 
cxxScopeGetAccess(void)124 enum CXXScopeAccess cxxScopeGetAccess(void)
125 {
126 	if(g_pScope->iCount < 1)
127 		return CXXScopeAccessUnknown;
128 	return (enum CXXScopeAccess)g_pScope->pTail->uInternalScopeAccess;
129 }
130 
cxxScopeGetName(void)131 const char * cxxScopeGetName(void)
132 {
133 	if(g_pScope->iCount < 1)
134 		return NULL;
135 	return vStringValue(g_pScope->pTail->pszWord);
136 }
137 
cxxScopeGetSize(void)138 int cxxScopeGetSize(void)
139 {
140 	return g_pScope->iCount;
141 }
142 
cxxScopeGetFullName(void)143 const char * cxxScopeGetFullName(void)
144 {
145 	if(!g_bScopeNameDirty)
146 		return g_szScopeName ? g_szScopeName->buffer : NULL;
147 
148 	if(g_pScope->iCount < 1)
149 	{
150 		g_bScopeNameDirty = false;
151 		return NULL;
152 	}
153 
154 	if(g_szScopeName)
155 		vStringClear(g_szScopeName);
156 	else
157 		g_szScopeName = vStringNew();
158 
159 	cxxTokenChainJoinInString(
160 			g_pScope,
161 			g_szScopeName,
162 			"::",
163 			CXXTokenChainJoinNoTrailingSpaces
164 		);
165 
166 	g_bScopeNameDirty = false;
167 	return g_szScopeName->buffer;
168 }
169 
cxxScopeGetFullNameAsString(void)170 vString * cxxScopeGetFullNameAsString(void)
171 {
172 	vString * ret;
173 
174 	if(!g_bScopeNameDirty)
175 	{
176 		ret = g_szScopeName;
177 		g_szScopeName = NULL;
178 		g_bScopeNameDirty = true;
179 		return ret;
180 	}
181 
182 	if(g_pScope->iCount < 1)
183 		return NULL;
184 
185 	if(g_szScopeName)
186 		vStringClear(g_szScopeName);
187 	else
188 		g_szScopeName = vStringNew();
189 
190 	cxxTokenChainJoinInString(
191 			g_pScope,
192 			g_szScopeName,
193 			"::",
194 			CXXTokenChainJoinNoTrailingSpaces
195 		);
196 
197 	ret = g_szScopeName;
198 	g_szScopeName = NULL;
199 	return ret;
200 }
201 
cxxScopeGetFullNameExceptLastComponentAsString(void)202 vString * cxxScopeGetFullNameExceptLastComponentAsString(void)
203 {
204 	if(g_pScope->iCount < 2)
205 		return NULL;
206 
207 	return cxxTokenChainJoinRange(
208 			g_pScope->pHead,
209 			g_pScope->pTail->pPrev,
210 			"::",
211 			CXXTokenChainJoinNoTrailingSpaces
212 		);
213 }
214 
215 
cxxScopeSetAccess(enum CXXScopeAccess eAccess)216 void cxxScopeSetAccess(enum CXXScopeAccess eAccess)
217 {
218 	if(g_pScope->iCount < 1)
219 		return; // warning?
220 	g_pScope->pTail->uInternalScopeAccess = (unsigned char)eAccess;
221 }
222 
cxxScopePushTop(CXXToken * t)223 void cxxScopePushTop(CXXToken * t)
224 {
225 	CXX_DEBUG_ASSERT(
226 			t->eType == CXXTokenTypeIdentifier,
227 			"The scope name must be an identifier"
228 		);
229 	CXX_DEBUG_ASSERT(
230 			t->pszWord,
231 			"The scope name should have a text"
232 		);
233 
234 	cxxTokenChainAppend(g_pScope,t);
235 	g_bScopeNameDirty = true;
236 
237 #ifdef CXX_DO_DEBUGGING
238 	const char * szScopeName = cxxScopeGetFullName();
239 
240 	CXX_DEBUG_PRINT("Pushed scope: '%s'",szScopeName ? szScopeName : "");
241 #endif
242 }
243 
cxxScopeTakeTop(void)244 CXXToken * cxxScopeTakeTop(void)
245 {
246 	CXX_DEBUG_ASSERT(
247 			g_pScope->iCount > 0,
248 			"When popping as scope there must be a scope to pop"
249 		);
250 
251 	CXXToken * t = cxxTokenChainTakeLast(g_pScope);
252 	g_bScopeNameDirty = true;
253 
254 #ifdef CXX_DO_DEBUGGING
255 	const char * szScopeName = cxxScopeGetFullName();
256 
257 	CXX_DEBUG_PRINT("Popped scope: '%s'",szScopeName ? szScopeName : "");
258 #endif
259 	return t;
260 }
261 
cxxScopePush(CXXToken * t,enum CXXScopeType eScopeType,enum CXXScopeAccess eInitialAccess)262 void cxxScopePush(
263 		CXXToken * t,
264 		enum CXXScopeType eScopeType,
265 		enum CXXScopeAccess eInitialAccess
266 	)
267 {
268 	t->uInternalScopeType = (unsigned char)eScopeType;
269 	t->uInternalScopeAccess = (unsigned char)eInitialAccess;
270 	cxxScopePushTop(t);
271 }
272 
cxxScopePop(void)273 void cxxScopePop(void)
274 {
275 	cxxTokenDestroy(cxxScopeTakeTop());
276 }
277