xref: /Universal-ctags/main/dependency.c (revision 4ecf2c99aeec8763f761fbca57ad18ea4f790639)
1 /*
2  *
3  *  Copyright (c) 2016, Red Hat, Inc.
4  *  Copyright (c) 2016, Masatake YAMATO
5  *
6  *  Author: Masatake YAMATO <yamato@redhat.com>
7  *
8  *   This source code is released for free distribution under the terms of the
9  *   GNU General Public License version 2 or (at your option) any later version.
10  *
11  */
12 
13 #include "general.h"  /* must always come first */
14 
15 #include "debug.h"
16 #include "dependency.h"
17 #include "options.h"
18 #include "parse_p.h"
19 #include "read.h"
20 #include "read_p.h"
21 #include "routines.h"
22 #include "subparser.h"
23 #include "subparser_p.h"
24 #include "xtag.h"
25 
26 #include <string.h>
27 
28 struct slaveControlBlock {
29 	slaveParser *slaveParsers;	/* The parsers on this list must be initialized when
30 								   this parser is initialized. */
31 	subparser   *subparsersDefault;
32 	subparser   *subparsersInUse;
33 	langType     owner;
34 };
35 
linkDependencyAtInitializeParsing(depType dtype,parserDefinition * const master,struct slaveControlBlock * masterSCB,struct kindControlBlock * masterKCB,parserDefinition * const slave,struct kindControlBlock * slaveKCB,void * data)36 extern void linkDependencyAtInitializeParsing (depType dtype,
37 						   parserDefinition *const master,
38 						   struct slaveControlBlock *masterSCB,
39 						   struct kindControlBlock *masterKCB,
40 						   parserDefinition *const slave,
41 						   struct kindControlBlock *slaveKCB,
42 						   void *data)
43 {
44 	if (dtype == DEPTYPE_KIND_OWNER)
45 		linkKindDependency (masterKCB, slaveKCB);
46 	else if (dtype == DEPTYPE_SUBPARSER || dtype == DEPTYPE_FOREIGNER)
47 	{
48 		slaveParser *s = xMalloc (1, slaveParser);
49 
50 		s->type = dtype;
51 		s->id = slave->id;
52 		s->data = data;
53 
54 		s->next = masterSCB->slaveParsers;
55 		masterSCB->slaveParsers = s;
56 	}
57 }
58 
attachSubparser(struct slaveControlBlock * base_sb,subparser * subparser)59 static void attachSubparser (struct slaveControlBlock *base_sb, subparser *subparser)
60 {
61 	   subparser->next = base_sb->subparsersDefault;
62 	   base_sb->subparsersDefault = subparser;
63 }
64 
65 
allocSlaveControlBlock(parserDefinition * parser)66 extern struct slaveControlBlock *allocSlaveControlBlock (parserDefinition *parser)
67 {
68 	struct slaveControlBlock *cb;
69 
70 	cb = xMalloc (1, struct slaveControlBlock);
71 	cb->slaveParsers = NULL;
72 	cb->subparsersDefault = NULL;
73 	cb->subparsersInUse = NULL;
74 	cb->owner = parser->id;
75 
76 	return cb;
77 }
78 
freeSlaveControlBlock(struct slaveControlBlock * cb)79 extern void freeSlaveControlBlock (struct slaveControlBlock *cb)
80 {
81 	eFree (cb);
82 }
83 
initializeDependencies(parserDefinition * parser,struct slaveControlBlock * cb)84 extern void initializeDependencies (parserDefinition *parser,
85 									struct slaveControlBlock *cb)
86 {
87 	unsigned int i;
88 	slaveParser *sp;
89 
90 	/* Initialize slaves */
91 	sp = cb->slaveParsers;
92 	while (sp != NULL)
93 	{
94 		if (sp->type == DEPTYPE_SUBPARSER)
95 		{
96 			subparser *sub;
97 
98 			sub = (subparser *)sp->data;
99 			sub->slaveParser = sp;
100 		}
101 
102 		if (sp->type == DEPTYPE_KIND_OWNER
103 			|| (sp->type == DEPTYPE_SUBPARSER &&
104 				(((subparser *)sp->data)->direction & SUBPARSER_BASE_RUNS_SUB)))
105 		{
106 			initializeParser (sp->id);
107 			if (sp->type == DEPTYPE_SUBPARSER
108 				&& isXtagEnabled (XTAG_SUBPARSER))
109 			{
110 				subparser *subparser = sp->data;
111 				attachSubparser (cb, subparser);
112 			}
113 		}
114 		sp = sp->next;
115 	}
116 
117 	/* Initialize masters that act as base parsers. */
118 	for (i = 0; i < parser->dependencyCount; i++)
119 	{
120 		parserDependency *d = parser->dependencies + i;
121 		if ((d->type == DEPTYPE_SUBPARSER &&
122 			 ((subparser *)(d->data))->direction & SUBPARSER_SUB_RUNS_BASE)
123 			|| (d->type == DEPTYPE_FOREIGNER))
124 		{
125 			langType baseParser;
126 			baseParser = getNamedLanguage (d->upperParser, 0);
127 			Assert (baseParser != LANG_IGNORE);
128 			initializeParser (baseParser);
129 		}
130 	}
131 }
132 
finalizeDependencies(parserDefinition * parser,struct slaveControlBlock * cb)133 extern void finalizeDependencies (parserDefinition *parser,
134 								  struct slaveControlBlock *cb)
135 {
136 	while (cb->slaveParsers)
137 	{
138 		slaveParser *sp = cb->slaveParsers;
139 		cb->slaveParsers = sp->next;
140 		sp->next = NULL;
141 		eFree (sp);
142 	}
143 }
144 
notifyInputStart(void)145 extern void notifyInputStart (void)
146 {
147 	subparser *s;
148 
149 	/* for running prelude of optlib */
150 	langType lang = getInputLanguage ();
151 	notifyLanguageRegexInputStart (lang);
152 
153 	foreachSubparser(s, true)
154 	{
155 		enterSubparser(s);
156 		if (s->inputStart)
157 			s->inputStart (s);
158 		/* propagate the event recursively */
159 		notifyInputStart ();
160 		leaveSubparser();
161 	}
162 }
163 
notifyInputEnd(void)164 extern void notifyInputEnd   (void)
165 {
166 	subparser *s;
167 
168 	foreachSubparser(s, true)
169 	{
170 		enterSubparser(s);
171 		/* propagate the event recursively */
172 		notifyInputEnd ();
173 		if (s->inputEnd)
174 			s->inputEnd (s);
175 		leaveSubparser();
176 	}
177 
178 	/* for running sequel of optlib */
179 	langType lang = getInputLanguage ();
180 	notifyLanguageRegexInputEnd (lang);
181 }
182 
notifyMakeTagEntry(const tagEntryInfo * tag,int corkIndex)183 extern void notifyMakeTagEntry (const tagEntryInfo *tag, int corkIndex)
184 {
185 	subparser *s;
186 
187 	foreachSubparser(s, false)
188 	{
189 		if (s->makeTagEntryNotify)
190 		{
191 			enterSubparser(s);
192 			s->makeTagEntryNotify (s, tag, corkIndex);
193 			leaveSubparser();
194 		}
195 	}
196 }
197 
getSubparserLanguage(subparser * s)198 extern langType getSubparserLanguage (subparser *s)
199 {
200 	return s->slaveParser->id;
201 }
202 
chooseExclusiveSubparser(subparser * s,void * data)203 extern void chooseExclusiveSubparser (subparser *s, void *data)
204 {
205 	if (s->exclusiveSubparserChosenNotify)
206 	{
207 		s->chosenAsExclusiveSubparser = true;
208 		enterSubparser(s);
209 		s->exclusiveSubparserChosenNotify (s, data);
210 		verbose ("%s is chosen as exclusive subparser\n",
211 				 getLanguageName (getSubparserLanguage (s)));
212 		leaveSubparser();
213 	}
214 }
215 
getFirstSubparser(struct slaveControlBlock * controlBlock)216 extern subparser *getFirstSubparser(struct slaveControlBlock *controlBlock)
217 {
218 	if (controlBlock)
219 		return controlBlock->subparsersInUse;
220 	return NULL;
221 }
222 
useDefaultSubparsers(struct slaveControlBlock * controlBlock)223 extern void useDefaultSubparsers (struct slaveControlBlock *controlBlock)
224 {
225 	controlBlock->subparsersInUse = controlBlock->subparsersDefault;
226 }
227 
useSpecifiedSubparser(struct slaveControlBlock * controlBlock,subparser * s)228 extern void useSpecifiedSubparser (struct slaveControlBlock *controlBlock, subparser *s)
229 {
230 	s->schedulingBaseparserExplicitly = true;
231 	controlBlock->subparsersInUse = s;
232 }
233 
setupSubparsersInUse(struct slaveControlBlock * controlBlock)234 extern void setupSubparsersInUse (struct slaveControlBlock *controlBlock)
235 {
236 	if (!controlBlock->subparsersInUse)
237 		useDefaultSubparsers(controlBlock);
238 }
239 
teardownSubparsersInUse(struct slaveControlBlock * controlBlock)240 extern subparser* teardownSubparsersInUse (struct slaveControlBlock *controlBlock)
241 {
242 	subparser *tmp;
243 	subparser *s = NULL;
244 
245 	tmp = controlBlock->subparsersInUse;
246 	controlBlock->subparsersInUse = NULL;
247 
248 	if (tmp && tmp->schedulingBaseparserExplicitly)
249 	{
250 		tmp->schedulingBaseparserExplicitly = false;
251 		s = tmp;
252 	}
253 
254 	if (s)
255 		return s;
256 
257 	while (tmp)
258 	{
259 		if (tmp->chosenAsExclusiveSubparser)
260 		{
261 			s = tmp;
262 		}
263 		tmp = tmp->next;
264 	}
265 
266 	return s;
267 }
268 
269 
270 static int subparserDepth;
271 
enterSubparser(subparser * subparser)272 extern void enterSubparser(subparser *subparser)
273 {
274 	subparserDepth++;
275 	pushLanguage (getSubparserLanguage (subparser));
276 }
277 
leaveSubparser(void)278 extern void leaveSubparser(void)
279 {
280 	popLanguage ();
281 	subparserDepth--;
282 }
283 
doesSubparserRun(void)284 extern bool doesSubparserRun (void)
285 {
286 	if (getLanguageForBaseParser () == getInputLanguage())
287 		return false;
288 	return subparserDepth;
289 }
290 
getFirstSlaveParser(struct slaveControlBlock * scb)291 extern slaveParser *getFirstSlaveParser (struct slaveControlBlock *scb)
292 {
293 	if (scb)
294 		return scb->slaveParsers;
295 	return NULL;
296 }
297 
getLanguageSubparser(langType sublang,bool including_none_crafted_parser)298 extern subparser *getLanguageSubparser (langType sublang,
299 										bool including_none_crafted_parser)
300 {
301 	subparser *s;
302 
303 	foreachSubparser (s, including_none_crafted_parser)
304 	{
305 		if (getSubparserLanguage (s) == sublang)
306 			return s;
307 	}
308 	return NULL;
309 }
310 
subparserColprintTableNew(void)311 extern struct colprintTable * subparserColprintTableNew (void)
312 {
313 	return colprintTableNew ("L:NAME", "L:BASEPARSER", "L:DIRECTIONS", NULL);
314 }
315 
subparserColprintAddSubparsers(struct colprintTable * table,struct slaveControlBlock * scb)316 extern void subparserColprintAddSubparsers (struct colprintTable *table,
317 											struct slaveControlBlock *scb)
318 {
319 	slaveParser *tmp;
320 
321 	pushLanguage (scb->owner);
322 	foreachSlaveParser(tmp)
323 	{
324 		if (tmp->type != DEPTYPE_SUBPARSER)
325 			continue;
326 
327 		if (!isLanguageVisible (tmp->id))
328 			continue;
329 
330 		struct colprintLine *line = colprintTableGetNewLine(table);
331 
332 		colprintLineAppendColumnCString (line, getLanguageName (tmp->id));
333 		colprintLineAppendColumnCString (line, getLanguageName (scb->owner));
334 
335 		const char *direction;
336 		switch (((subparser *)tmp->data)->direction)
337 		{
338 		case SUBPARSER_BASE_RUNS_SUB:
339 			direction = "base => sub {shared}";
340 			break;
341 		case SUBPARSER_SUB_RUNS_BASE:
342 			direction = "base <= sub {dedicated}";
343 			break;
344 		case SUBPARSER_BI_DIRECTION:
345 			direction = "base <> sub {bidirectional}";
346 			break;
347 		default:
348 			direction  = "UNKNOWN(INTERNAL BUG)";
349 			break;
350 		}
351 		colprintLineAppendColumnCString (line, direction);
352 	}
353 	popLanguage ();
354 }
355 
subparserColprintCompareLines(struct colprintLine * a,struct colprintLine * b)356 static int subparserColprintCompareLines (struct colprintLine *a , struct colprintLine *b)
357 {
358 	const char *a_name = colprintLineGetColumn (a, 0);
359 	const char *b_name = colprintLineGetColumn (b, 0);
360 
361 	int r;
362 	r = strcmp (a_name, b_name);
363 	if (r != 0)
364 		return r;
365 
366 	const char *a_baseparser = colprintLineGetColumn (a, 1);
367 	const char *b_baseparser = colprintLineGetColumn (b, 1);
368 
369 	return strcmp(a_baseparser, b_baseparser);
370 }
371 
subparserColprintTablePrint(struct colprintTable * table,bool withListHeader,bool machinable,FILE * fp)372 extern void subparserColprintTablePrint (struct colprintTable *table,
373 										 bool withListHeader, bool machinable, FILE *fp)
374 {
375 	colprintTableSort (table, subparserColprintCompareLines);
376 	colprintTablePrint (table, 0, withListHeader, machinable, fp);
377 }
378