xref: /Universal-ctags/parsers/r-r6class.c (revision 2b0000354518fbf34f719f1b6af5f8d0d0bec916)
1 /*
2 *   Copyright (c) 2020, Masatake YAMATO
3 *   Copyright (c) 2020, Red Hat, Inc.
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 generating tags for R6Class.
9 *   https://www.rdocumentation.org/packages/R6/versions/2.4.1/topics/R6Class
10 */
11 
12 
13 /*
14 *   INCLUDE FILES
15 */
16 #include "general.h"	/* must always come first */
17 
18 #include "r.h"
19 #include "kind.h"
20 #include "parse.h"
21 #include "entry.h"
22 #include "tokeninfo.h"
23 #include "read.h"
24 
25 #include <string.h>
26 
27 
28 /*
29 *   DATA DECLARATIONS
30 */
31 
32 struct r6Subparser {
33 	rSubparser r;
34 	const char * access;
35 	bool activeBinding;
36 };
37 
38 /*
39 * FUNCTION PROTOTYPES
40 */
41 
42 static int r6ReadRightSideSymbol (rSubparser *s,
43 								  tokenInfo *const symbol,
44 								  const char *const assignmentOperator,
45 								  int parent,
46 								  tokenInfo *const token);
47 static int r6MakeTagWithTranslation (rSubparser *s,
48 									 tokenInfo *const token,
49 									 int parent,
50 									 bool in_func,
51 									 int kindInR,
52 									 const char *const assignmentOperator);
53 static bool r6AskTagAcceptancy (rSubparser *s, tagEntryInfo *pe);
54 static bool r6HasFunctionAlikeKind (rSubparser *s, tagEntryInfo *e);
55 
56 static void parseClass (rSubparser *s, tokenInfo *const token, int classIndex);
57 
58 
59 /*
60 *   DATA DEFINITIONS
61 */
62 
63 typedef enum {
64 	R6_K_CLASS,
65 	R6_K_METHOD,
66 	R6_K_FIELD,
67 	R6_K_ACTIVE_BINDING_FUNCTION,
68 } r6Kind;
69 
70 static kindDefinition R6Kinds[] = {
71 	{ true, 'c', "class",  "classes" },
72 	{ true, 'm', "method", "methods" },
73 	{ true, 'f', "field",  "fields" },
74 	{ true, 'a', "activeBindingFunc", "active binding functions" },
75 };
76 
77 static struct r6Subparser r6Subparser = {
78 	.r = {
79 		.subparser = {
80 			.direction = SUBPARSER_BI_DIRECTION,
81 		},
82 		.readRightSideSymbol = r6ReadRightSideSymbol,
83 		.makeTagWithTranslation = r6MakeTagWithTranslation,
84 		.askTagAcceptancy = r6AskTagAcceptancy,
85 		.hasFunctionAlikeKind = r6HasFunctionAlikeKind,
86 	},
87 	.access = NULL,
88 	.activeBinding = false,
89 };
90 
91 
92 /*
93 *   FUNCTION DEFINITIONS
94 */
95 
96 /*
97  *       parse this area:              V======V
98  * klass = R6Class("klass", ..., inherit=parent)
99  */
parseInherit(rSubparser * s,tokenInfo * const token,int classIndex)100 static void parseInherit (rSubparser *s,
101 							tokenInfo *const token, int classIndex)
102 {
103 	rTokenReadNoNewline (token);
104 	if (tokenIsTypeVal (token, '='))
105 	{
106 		rTokenReadNoNewline (token);
107 		if (tokenIsType (token, R_SYMBOL))
108 		{
109 			tagEntryInfo *e = getEntryInCorkQueue (classIndex);
110 			e->extensionFields.inheritance = vStringStrdup (token->string);
111 		}
112 		else
113 			tokenUnread (token);
114 	}
115 	else
116 		tokenUnread (token);
117 }
118 
119 /*
120  *       parse this area:              V===V              V===V             V===V
121  * klass = R6Class("klass", public=list(...), private=list(...), active=list(...), ...)
122  */
parseListMain(rSubparser * s,tokenInfo * const token,int classIndex,const char * access,bool activeBinding)123 static void parseListMain (rSubparser *s,
124 							 tokenInfo *const token, int classIndex, const char *access,
125 							 bool activeBinding)
126 {
127 	const char *last_access = ((struct r6Subparser *)s)->access;
128 	((struct r6Subparser *)s)->access = access;
129 
130 	bool last_active_binding = ((struct r6Subparser *)s)->activeBinding;
131 	((struct r6Subparser *)s)->activeBinding = activeBinding;
132 
133 	rTokenReadNoNewline (token);
134 
135 	while (! tokenIsTypeVal (token, ')'))
136 	{
137 		if (!rParseStatement (token, classIndex, false))
138 			break;
139 		else if (tokenIsTypeVal (token, '\n'))
140 			rTokenReadNoNewline (token);
141 	}
142 	((struct r6Subparser *)s)->access = last_access;
143 	((struct r6Subparser *)s)->activeBinding = last_active_binding;
144 }
145 
146 /*
147  *       parse this area:        V=====|---V        V=====|---V       V=====|---V
148  * klass = R6Class("klass", public=list(...), private=list(...), active=list(...), ...)
149  */
parseList(rSubparser * s,tokenInfo * const token,int classIndex,const char * access,bool activeBinding)150 static void parseList (rSubparser *s,
151 					   tokenInfo *const token, int classIndex, const char *access,
152 					   bool activeBinding)
153 {
154 	rTokenReadNoNewline (token);
155 	if (tokenIsTypeVal (token, '='))
156 	{
157 		rTokenReadNoNewline (token);
158 		if (tokenIsKeyword (token, R_LIST))
159 		{
160 			rTokenReadNoNewline (token);
161 			if (tokenIsTypeVal (token, '('))
162 				parseListMain (s, token, classIndex, access, activeBinding);
163 			else
164 				tokenUnread (token);
165 		}
166 		else
167 			tokenUnread (token);
168 	}
169 	else
170 		tokenUnread (token);
171 }
172 
173 /*
174  *      parse this area: V=======|----V=======|----V======|----V=======|----V
175  * klass = R6Class("klass", public=..., private=..., active=..., inherit=...)
176  */
parseClass(rSubparser * s,tokenInfo * const token,int classIndex)177 static void parseClass (rSubparser *s,
178 						  tokenInfo *const token, int classIndex)
179 {
180 	do
181 	{
182 		rTokenReadNoNewline (token);
183 
184 		if (tokenIsTypeVal (token, ')'))
185 			break;
186 		else if (tokenIsTypeVal (token, '('))
187 			tokenSkipOverPair (token);
188 		else if (tokenIsTypeVal (token, '{'))
189 			tokenSkipOverPair (token);
190 		else if (tokenIsTypeVal (token, '['))
191 			tokenSkipOverPair (token);
192 		else if (tokenIsType (token, R_SYMBOL))
193 		{
194 			const char *str = tokenString (token);
195 			if (strcmp (str, "inherit") == 0)
196 				parseInherit (s, token, classIndex);
197 			else if (strcmp (str, "public") == 0)
198 				parseList (s, token, classIndex, "public", false);
199 			else if (strcmp (str, "private") == 0)
200 				parseList (s, token, classIndex, "private", false);
201 			else if (strcmp (str, "active") == 0)
202 				parseList (s, token, classIndex, "public", true);
203 		}
204 	}
205 	while (!tokenIsEOF (token));
206 }
207 
208 /*
209  *         V=============|-----V: parse this area
210  * klass = R6Class("klass", ...)
211  */
r6ReadRightSideSymbol(rSubparser * s,tokenInfo * const symbol,const char * const assignmentOperator,int parent,tokenInfo * const token)212 static int r6ReadRightSideSymbol (rSubparser *s,
213 								  tokenInfo *const symbol,
214 								  const char *const assignmentOperator,
215 								  int parent,
216 								  tokenInfo *const token)
217 {
218 	tokenInfo * token0 = NULL;
219 	tokenInfo * token1 = NULL;
220 	if (strcmp (tokenString (token), "R6") == 0)
221 	{
222 		tokenInfo * token0 = rNewToken ();
223 		tokenRead (token0);
224 		if (!tokenIsType (token0, R_SCOPE))
225 			goto reject;
226 		if (strcmp (tokenString (token0), "::"))
227 			goto reject;
228 
229 		tokenInfo * token1 = rNewToken ();
230 		tokenRead (token1);
231 		if (!tokenIsType (token1, R_SYMBOL))
232 			goto reject;
233 		if (strcmp (tokenString (token1), "R6Class"))
234 			goto reject;
235 		tokenCopy (token, token1);
236 		tokenDelete (token1);
237 		tokenDelete (token0);
238 		token0 = token1 = NULL;
239 	}
240 	else if (strcmp (tokenString (token), "R6Class") != 0)
241 		return CORK_NIL;
242 
243 	rTokenReadNoNewline (token);
244 	if (tokenIsTypeVal (token, '('))
245 	{
246 		int corkIndex = makeSimpleTag (symbol->string, R6_K_CLASS);
247 		tagEntryInfo *e = getEntryInCorkQueue (corkIndex);
248 		if (e)
249 			e->extensionFields.scopeIndex = parent;
250 		parseClass (s, token, corkIndex);
251 		return corkIndex;
252 	}
253 	return CORK_NIL;
254  reject:
255 	if (token1)
256 		tokenUnread (token1);
257 	if (token0)
258 		tokenUnread (token0);
259 	/* tokenDelete accepts NULL. */
260 	tokenDelete (token1);
261 	tokenDelete (token0);
262 
263 	return CORK_NIL;
264 }
265 
r6MakeTagWithTranslation(rSubparser * s,tokenInfo * const token,int parent,bool in_func,int kindInR,const char * const assignmentOperator)266 static int r6MakeTagWithTranslation (rSubparser *s,
267 									 tokenInfo *const token,
268 									 int parent,
269 									 bool in_func,
270 									 int kindInR,
271 									 const char *const assignmentOperator)
272 {
273 	tagEntryInfo e;
274 
275 	initTagEntry (&e, tokenString (token),
276 				  in_func
277 				  ? (((struct r6Subparser*)s)->activeBinding
278 					 ? R6_K_ACTIVE_BINDING_FUNCTION
279 					 : R6_K_METHOD)
280 				  : R6_K_FIELD);
281 	e.extensionFields.scopeIndex = parent;
282 	e.extensionFields.access = ((struct r6Subparser*)s)->access;
283 
284 	return makeTagEntry (&e);
285 }
286 
r6AskTagAcceptancy(rSubparser * s,tagEntryInfo * pe)287 static bool r6AskTagAcceptancy (rSubparser *s, tagEntryInfo *pe)
288 {
289 	return (pe->kindIndex == R6_K_CLASS);
290 }
291 
r6HasFunctionAlikeKind(rSubparser * s,tagEntryInfo * e)292 static bool r6HasFunctionAlikeKind (rSubparser *s,
293 									tagEntryInfo *e)
294 {
295 	return e->kindIndex == R6_K_METHOD ||
296 		e->kindIndex == R6_K_ACTIVE_BINDING_FUNCTION;
297 }
298 
findR6Tags(void)299 static void findR6Tags(void)
300 {
301 	r6Subparser.access = NULL;
302 	scheduleRunningBaseparser (RUN_DEFAULT_SUBPARSERS);
303 }
304 
R6ClassParser(void)305 extern parserDefinition* R6ClassParser (void)
306 {
307 	parserDefinition* const def = parserNew("R6Class");
308 
309 	static parserDependency dependencies [] = {
310 		[0] = { DEPTYPE_SUBPARSER, "R", &r6Subparser },
311 	};
312 
313 	def->dependencies = dependencies;
314 	def->dependencyCount = ARRAY_SIZE (dependencies);
315 
316 	def->kindTable = R6Kinds;
317 	def->kindCount = ARRAY_SIZE(R6Kinds);
318 
319 	def->parser =  findR6Tags;
320 	def->useCork = CORK_QUEUE;
321 
322 	return def;
323 }
324