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