xref: /Universal-ctags/parsers/itcl.c (revision a2d077b30c9a7d7ba619cbbf85e7190fbfdec1a4)
16ae73029SMasatake YAMATO /*
26ae73029SMasatake YAMATO *   Copyright (c) 2017, Masatake YAMATO
36ae73029SMasatake YAMATO *
46ae73029SMasatake YAMATO *   This source code is released for free distribution under the terms of the
56ae73029SMasatake YAMATO *   GNU General Public License version 2 or (at your option) any later version.
66ae73029SMasatake YAMATO *
76ae73029SMasatake YAMATO */
86ae73029SMasatake YAMATO 
96ae73029SMasatake YAMATO #include "general.h"  /* must always come first */
106ae73029SMasatake YAMATO #include "tcl.h"
116ae73029SMasatake YAMATO #include "entry.h"
12cecb4a16SMasatake YAMATO #include "param.h"
136ae73029SMasatake YAMATO #include "parse.h"
1494e60171SMasatake YAMATO #include "read.h"
1594e60171SMasatake YAMATO #include "keyword.h"
166ae73029SMasatake YAMATO 
174952911fSMasatake YAMATO #include <string.h>
184952911fSMasatake YAMATO 
194952911fSMasatake YAMATO 
20e07c5f05SMasatake YAMATO struct itclSubparser {
21e07c5f05SMasatake YAMATO 	tclSubparser tcl;
22a87043aeSMasatake YAMATO 	bool foundITclNamespaceImported;
23e07c5f05SMasatake YAMATO };
24e07c5f05SMasatake YAMATO 
2594e60171SMasatake YAMATO static scopeSeparator ITclGenericSeparators [] = {
26f92e6bf2SMasatake YAMATO 	{ KIND_WILDCARD_INDEX, "::" },
2794e60171SMasatake YAMATO };
2894e60171SMasatake YAMATO 
2994e60171SMasatake YAMATO enum ITclKind {
306ae73029SMasatake YAMATO 	K_CLASS,
316ae73029SMasatake YAMATO 	K_METHOD,
3294e60171SMasatake YAMATO 	K_VARIABLE,
3394e60171SMasatake YAMATO 	K_COMMON,
3494e60171SMasatake YAMATO 	K_PROC,
356ae73029SMasatake YAMATO };
366ae73029SMasatake YAMATO 
376ae73029SMasatake YAMATO static kindDefinition ITclKinds[] = {
386ae73029SMasatake YAMATO 	{ true, 'c', "class", "classes" },
3994e60171SMasatake YAMATO 	{ true, 'm', "method", "methods",
4094e60171SMasatake YAMATO 	  ATTACH_SEPARATORS(ITclGenericSeparators)},
4194e60171SMasatake YAMATO 	{ true, 'v', "variable", "object-specific variables",
4294e60171SMasatake YAMATO 	  ATTACH_SEPARATORS(ITclGenericSeparators)},
4394e60171SMasatake YAMATO 	{ true, 'C', "common", "common variables",
4494e60171SMasatake YAMATO 	  ATTACH_SEPARATORS(ITclGenericSeparators)},
4594e60171SMasatake YAMATO 	{ true, 'p', "procedure", "procedures within the  class  namespace",
4694e60171SMasatake YAMATO 	  ATTACH_SEPARATORS(ITclGenericSeparators)},
476ae73029SMasatake YAMATO };
486ae73029SMasatake YAMATO 
4994e60171SMasatake YAMATO enum {
5094e60171SMasatake YAMATO 	KEYWORD_INHERIT,
5194e60171SMasatake YAMATO 	KEYWORD_METHOD,
5294e60171SMasatake YAMATO 	KEYWORD_PRIVATE,
5394e60171SMasatake YAMATO 	KEYWORD_PROTECTED,
5494e60171SMasatake YAMATO 	KEYWORD_PUBLIC,
5594e60171SMasatake YAMATO 	KEYWORD_VARIABLE,
5694e60171SMasatake YAMATO 	KEYWORD_COMMON,
5794e60171SMasatake YAMATO 	KEYWORD_PROC,
5894e60171SMasatake YAMATO };
5994e60171SMasatake YAMATO 
6094e60171SMasatake YAMATO typedef int keywordId; /* to allow KEYWORD_NONE */
6194e60171SMasatake YAMATO 
6294e60171SMasatake YAMATO static const keywordTable ITclKeywordTable[] = {
6394e60171SMasatake YAMATO 	/* keyword			keyword ID */
6494e60171SMasatake YAMATO 	{ "inherit",		KEYWORD_INHERIT		},
6594e60171SMasatake YAMATO 	{ "method",			KEYWORD_METHOD		},
6694e60171SMasatake YAMATO 	{ "private",		KEYWORD_PRIVATE		},
6794e60171SMasatake YAMATO 	{ "protected",		KEYWORD_PROTECTED	},
6894e60171SMasatake YAMATO 	{ "public",			KEYWORD_PUBLIC		},
6994e60171SMasatake YAMATO 	{ "variable",		KEYWORD_VARIABLE	},
7094e60171SMasatake YAMATO 	{ "common",			KEYWORD_COMMON		},
7194e60171SMasatake YAMATO 	{ "proc",			KEYWORD_PROC		},
7294e60171SMasatake YAMATO };
7394e60171SMasatake YAMATO 
74cecb4a16SMasatake YAMATO static bool itclForceUse;
75cecb4a16SMasatake YAMATO 
resolveKeyword(vString * string)7694e60171SMasatake YAMATO static keywordId resolveKeyword (vString *string)
7794e60171SMasatake YAMATO {
7894e60171SMasatake YAMATO 	char *s = vStringValue (string);
7994e60171SMasatake YAMATO 	static langType lang = LANG_AUTO;
8094e60171SMasatake YAMATO 
8194e60171SMasatake YAMATO 	if (lang == LANG_AUTO)
8294e60171SMasatake YAMATO 		lang = getInputLanguage ();
8394e60171SMasatake YAMATO 
8494e60171SMasatake YAMATO 	return lookupKeyword (s, lang);
8594e60171SMasatake YAMATO }
8694e60171SMasatake YAMATO 
parseInherit(tokenInfo * token,int r)8794e60171SMasatake YAMATO static void parseInherit (tokenInfo *token, int r)
8894e60171SMasatake YAMATO {
8994e60171SMasatake YAMATO 	vString *inherits = vStringNew ();
9094e60171SMasatake YAMATO 
9194e60171SMasatake YAMATO 	do {
9294e60171SMasatake YAMATO 		tokenRead (token);
9394e60171SMasatake YAMATO 		if (tokenIsType (token, TCL_IDENTIFIER))
9494e60171SMasatake YAMATO 		{
9594e60171SMasatake YAMATO 			if (vStringLength(inherits) != 0)
9694e60171SMasatake YAMATO 				vStringPut (inherits, ',');
9794e60171SMasatake YAMATO 			vStringCat(inherits, token->string);
9894e60171SMasatake YAMATO 		}
9994e60171SMasatake YAMATO 		else if (tokenIsType(token, TCL_EOL))
10094e60171SMasatake YAMATO 			break;
10194e60171SMasatake YAMATO 		else
10294e60171SMasatake YAMATO 		{
10394e60171SMasatake YAMATO 			skipToEndOfTclCmdline (token);
10494e60171SMasatake YAMATO 			break;
10594e60171SMasatake YAMATO 		}
10694e60171SMasatake YAMATO 	} while (1);
10794e60171SMasatake YAMATO 
10894e60171SMasatake YAMATO 	if (vStringLength(inherits) > 0)
10994e60171SMasatake YAMATO 	{
11094e60171SMasatake YAMATO 		tagEntryInfo *e = getEntryInCorkQueue (r);
11194e60171SMasatake YAMATO 		if (e)
11294e60171SMasatake YAMATO 		{
11394e60171SMasatake YAMATO 			e->extensionFields.inheritance = vStringDeleteUnwrap (inherits);
11494e60171SMasatake YAMATO 			return;
11594e60171SMasatake YAMATO 		}
11694e60171SMasatake YAMATO 	}
11794e60171SMasatake YAMATO 
11894e60171SMasatake YAMATO 	vStringDelete (inherits);
11994e60171SMasatake YAMATO }
12094e60171SMasatake YAMATO 
attachProtectionMaybe(tagEntryInfo * e,keywordId protection)12194e60171SMasatake YAMATO static void attachProtectionMaybe(tagEntryInfo *e, keywordId protection)
12294e60171SMasatake YAMATO {
12394e60171SMasatake YAMATO 		switch (protection)
12494e60171SMasatake YAMATO 		{
12594e60171SMasatake YAMATO 		case KEYWORD_PROTECTED:
1261c5b56fcSMasatake YAMATO 			e->extensionFields.access = "protected";
12794e60171SMasatake YAMATO 			break;
12894e60171SMasatake YAMATO 		case KEYWORD_PRIVATE:
1291c5b56fcSMasatake YAMATO 			e->extensionFields.access = "private";
13094e60171SMasatake YAMATO 			break;
13194e60171SMasatake YAMATO 		case KEYWORD_PUBLIC:
1321c5b56fcSMasatake YAMATO 			e->extensionFields.access = "public";
13394e60171SMasatake YAMATO 			break;
13494e60171SMasatake YAMATO 		}
13594e60171SMasatake YAMATO }
13694e60171SMasatake YAMATO 
parseSubobject(tokenInfo * token,int parent,enum ITclKind kind,keywordId protection)13794e60171SMasatake YAMATO static void parseSubobject (tokenInfo *token, int parent, enum ITclKind kind, keywordId protection)
1386ae73029SMasatake YAMATO {
1396ae73029SMasatake YAMATO 	int r = CORK_NIL;
1406ae73029SMasatake YAMATO 
14194e60171SMasatake YAMATO 	tokenRead (token);
14294e60171SMasatake YAMATO 	if (tokenIsType (token, TCL_IDENTIFIER))
14394e60171SMasatake YAMATO 	{
14494e60171SMasatake YAMATO 		tagEntryInfo e;
14594e60171SMasatake YAMATO 
14616a2541cSMasatake YAMATO 		initTagEntry(&e, vStringValue (token->string), kind);
14794e60171SMasatake YAMATO 		e.extensionFields.scopeIndex = parent;
14894e60171SMasatake YAMATO 		attachProtectionMaybe (&e, protection);
14994e60171SMasatake YAMATO 		r = makeTagEntry (&e);
15094e60171SMasatake YAMATO 	}
15194e60171SMasatake YAMATO 
15294e60171SMasatake YAMATO 	skipToEndOfTclCmdline (token);
15394e60171SMasatake YAMATO 	tagEntryInfo *e = getEntryInCorkQueue (r);
1543671ad72SMasatake YAMATO 	if (e)
15594e60171SMasatake YAMATO 		e->extensionFields.endLine = token->lineNumber;
15694e60171SMasatake YAMATO }
15794e60171SMasatake YAMATO 
15894e60171SMasatake YAMATO 
parseVariable(tokenInfo * token,int r,keywordId protection)15994e60171SMasatake YAMATO static void parseVariable (tokenInfo *token, int r, keywordId protection)
16094e60171SMasatake YAMATO {
16194e60171SMasatake YAMATO 	parseSubobject(token, r, K_VARIABLE, protection);
16294e60171SMasatake YAMATO }
16394e60171SMasatake YAMATO 
parseMethod(tokenInfo * token,int r,keywordId protection)16494e60171SMasatake YAMATO static void parseMethod (tokenInfo *token, int r, keywordId protection)
16594e60171SMasatake YAMATO {
16694e60171SMasatake YAMATO 	parseSubobject(token, r, K_METHOD, protection);
16794e60171SMasatake YAMATO }
16894e60171SMasatake YAMATO 
parseProc(tokenInfo * token,int r,keywordId protection)16994e60171SMasatake YAMATO static void parseProc (tokenInfo *token, int r, keywordId protection)
17094e60171SMasatake YAMATO {
17194e60171SMasatake YAMATO 	parseSubobject(token, r, K_PROC, protection);
17294e60171SMasatake YAMATO }
17394e60171SMasatake YAMATO 
parseCommon(tokenInfo * token,int r,keywordId protection)17494e60171SMasatake YAMATO static void parseCommon (tokenInfo *token, int r, keywordId protection)
17594e60171SMasatake YAMATO {
17694e60171SMasatake YAMATO 	parseSubobject(token, r, K_COMMON, protection);
17794e60171SMasatake YAMATO }
17894e60171SMasatake YAMATO 
parseClass(tclSubparser * s CTAGS_ATTR_UNUSED,int parentIndex,void * pstate)1795d9d66cfSMasatake YAMATO static int parseClass (tclSubparser *s CTAGS_ATTR_UNUSED, int parentIndex,
1805d9d66cfSMasatake YAMATO 					   void *pstate)
1816ae73029SMasatake YAMATO {
1825d9d66cfSMasatake YAMATO 	tokenInfo *token = newTclToken (pstate);
18394e60171SMasatake YAMATO 	int r = CORK_NIL;
1846ae73029SMasatake YAMATO 
1856ae73029SMasatake YAMATO 	tokenRead (token);
1866ae73029SMasatake YAMATO 	if (tokenIsType (token, TCL_IDENTIFIER))
1876ae73029SMasatake YAMATO 	{
1886ae73029SMasatake YAMATO 		tagEntryInfo e;
1896ae73029SMasatake YAMATO 
19016a2541cSMasatake YAMATO 		initTagEntry(&e, vStringValue (token->string), K_CLASS);
1916ae73029SMasatake YAMATO 		e.extensionFields.scopeIndex = parentIndex;
1926ae73029SMasatake YAMATO 		r = makeTagEntry (&e);
1936ae73029SMasatake YAMATO 	}
19494e60171SMasatake YAMATO 
19594e60171SMasatake YAMATO 	if (tokenSkipToType (token, '{'))
1966ae73029SMasatake YAMATO 	{
19794e60171SMasatake YAMATO 		keywordId protection = KEYWORD_NONE;
19894e60171SMasatake YAMATO 
19994e60171SMasatake YAMATO 		do {
2006ae73029SMasatake YAMATO 			tokenRead (token);
201affb14f4SMasatake YAMATO 			if (tokenIsType (token, TCL_IDENTIFIER)
202affb14f4SMasatake YAMATO 				|| tokenIsType (token, TCL_KEYWORD))
2036ae73029SMasatake YAMATO 			{
20494e60171SMasatake YAMATO 				keywordId k = resolveKeyword (token->string);
20594e60171SMasatake YAMATO 				switch (k)
20694e60171SMasatake YAMATO 				{
20794e60171SMasatake YAMATO 				case KEYWORD_INHERIT:
20894e60171SMasatake YAMATO 					parseInherit(token, r);
20994e60171SMasatake YAMATO 					protection = KEYWORD_NONE;
21094e60171SMasatake YAMATO 					break;
21194e60171SMasatake YAMATO 				case KEYWORD_VARIABLE:
21294e60171SMasatake YAMATO 					parseVariable(token, r, protection);
21394e60171SMasatake YAMATO 					protection = KEYWORD_NONE;
21494e60171SMasatake YAMATO 					break;
21594e60171SMasatake YAMATO 				case KEYWORD_METHOD:
21694e60171SMasatake YAMATO 					parseMethod(token, r, protection);
21794e60171SMasatake YAMATO 					protection = KEYWORD_NONE;
21894e60171SMasatake YAMATO 					break;
21994e60171SMasatake YAMATO 				case KEYWORD_COMMON:
22094e60171SMasatake YAMATO 					parseCommon(token, r, protection);
22194e60171SMasatake YAMATO 					protection = KEYWORD_NONE;
22294e60171SMasatake YAMATO 					break;
22394e60171SMasatake YAMATO 				case KEYWORD_PUBLIC:
22494e60171SMasatake YAMATO 				case KEYWORD_PROTECTED:
22594e60171SMasatake YAMATO 				case KEYWORD_PRIVATE:
22694e60171SMasatake YAMATO 					protection = k;
22794e60171SMasatake YAMATO 					continue;
228affb14f4SMasatake YAMATO 				case KEYWORD_PROC:
229affb14f4SMasatake YAMATO 					parseProc(token, r, protection);
230affb14f4SMasatake YAMATO 					protection = KEYWORD_NONE;
231affb14f4SMasatake YAMATO 					break;
23294e60171SMasatake YAMATO 				default:
23394e60171SMasatake YAMATO 					protection = KEYWORD_NONE;
23494e60171SMasatake YAMATO 					skipToEndOfTclCmdline (token);
23594e60171SMasatake YAMATO 					break;
2366ae73029SMasatake YAMATO 				}
2376ae73029SMasatake YAMATO 			}
23894e60171SMasatake YAMATO 			else if (token->type == '}')
23994e60171SMasatake YAMATO 			{
24094e60171SMasatake YAMATO 				protection = KEYWORD_NONE;
24194e60171SMasatake YAMATO 				break;
24294e60171SMasatake YAMATO 			}
2436ae73029SMasatake YAMATO 			else
24494e60171SMasatake YAMATO 			{
24594e60171SMasatake YAMATO 				protection = KEYWORD_NONE;
24694e60171SMasatake YAMATO 				skipToEndOfTclCmdline (token);
2476ae73029SMasatake YAMATO 			}
24894e60171SMasatake YAMATO 		} while (!tokenIsEOF(token));
24994e60171SMasatake YAMATO 	}
25094e60171SMasatake YAMATO 
251a203ce0eSMasatake YAMATO 	tokenDelete(token);
25294e60171SMasatake YAMATO 	return r;
25394e60171SMasatake YAMATO }
25494e60171SMasatake YAMATO 
commandNotify(tclSubparser * s,char * command,int parentIndex,void * pstate)25594e60171SMasatake YAMATO static int commandNotify (tclSubparser *s, char *command,
2565d9d66cfSMasatake YAMATO 						  int parentIndex, void *pstate)
25794e60171SMasatake YAMATO {
258e07c5f05SMasatake YAMATO 	struct itclSubparser *itcl = (struct itclSubparser *)s;
25994e60171SMasatake YAMATO 	int r = CORK_NIL;
26094e60171SMasatake YAMATO 
261a87043aeSMasatake YAMATO 	if ((itcl->foundITclNamespaceImported
262a87043aeSMasatake YAMATO 		 && (strcmp (command, "class") == 0))
26394e60171SMasatake YAMATO 		|| (strcmp (command, "itcl::class") == 0))
2645d9d66cfSMasatake YAMATO 		r = parseClass (s, parentIndex, pstate);
26594e60171SMasatake YAMATO 
2666ae73029SMasatake YAMATO 	return r;
2676ae73029SMasatake YAMATO }
2686ae73029SMasatake YAMATO 
namespaceImportNotify(tclSubparser * s,char * namespace,void * pstate CTAGS_ATTR_UNUSED)2695d9d66cfSMasatake YAMATO static void namespaceImportNotify (tclSubparser *s, char *namespace,
2705d9d66cfSMasatake YAMATO 								   void *pstate CTAGS_ATTR_UNUSED)
271a87043aeSMasatake YAMATO {
272a87043aeSMasatake YAMATO 	struct itclSubparser *itcl = (struct itclSubparser *)s;
273a87043aeSMasatake YAMATO 
274a87043aeSMasatake YAMATO 	if (strcmp(namespace, "itcl::*") == 0
275a87043aeSMasatake YAMATO 		|| strcmp(namespace, "itcl::class") == 0)
276a87043aeSMasatake YAMATO 		itcl->foundITclNamespaceImported = true;
277a87043aeSMasatake YAMATO }
278a87043aeSMasatake YAMATO 
inputStart(subparser * s)279e07c5f05SMasatake YAMATO static void inputStart (subparser *s)
280e07c5f05SMasatake YAMATO {
281e07c5f05SMasatake YAMATO 	struct itclSubparser *itcl = (struct itclSubparser *)s;
282e07c5f05SMasatake YAMATO 
283cecb4a16SMasatake YAMATO 	itcl->foundITclNamespaceImported = itclForceUse;
284e07c5f05SMasatake YAMATO }
285e07c5f05SMasatake YAMATO 
286*a2d077b3SMasatake YAMATO static struct itclSubparser itclSubparser = {
287e07c5f05SMasatake YAMATO 	.tcl = {
288e07c5f05SMasatake YAMATO 		.subparser = {
289e07c5f05SMasatake YAMATO 			.direction = SUBPARSER_BI_DIRECTION,
290e07c5f05SMasatake YAMATO 			.inputStart = inputStart,
291e07c5f05SMasatake YAMATO 		},
292e07c5f05SMasatake YAMATO 		.commandNotify = commandNotify,
293a87043aeSMasatake YAMATO 		.namespaceImportNotify = namespaceImportNotify,
294e07c5f05SMasatake YAMATO 	},
295e07c5f05SMasatake YAMATO };
296e07c5f05SMasatake YAMATO 
findITclTags(void)2976ae73029SMasatake YAMATO static void findITclTags(void)
2986ae73029SMasatake YAMATO {
2996ae73029SMasatake YAMATO 	scheduleRunningBaseparser (RUN_DEFAULT_SUBPARSERS);
3006ae73029SMasatake YAMATO }
3016ae73029SMasatake YAMATO 
itclForceUseParamHandler(const langType language CTAGS_ATTR_UNUSED,const char * name,const char * arg)302cecb4a16SMasatake YAMATO static void itclForceUseParamHandler (const langType language CTAGS_ATTR_UNUSED,
303cecb4a16SMasatake YAMATO 									  const char *name, const char *arg)
304cecb4a16SMasatake YAMATO {
305cecb4a16SMasatake YAMATO 	itclForceUse = paramParserBool (arg, itclForceUse, name, "parameter");
306cecb4a16SMasatake YAMATO }
307cecb4a16SMasatake YAMATO 
308cecb4a16SMasatake YAMATO static parameterHandlerTable ItclParameterHandlerTable [] = {
309cecb4a16SMasatake YAMATO 	{ .name = "forceUse",
310cecb4a16SMasatake YAMATO 	  .desc = "enable the parser even when `itcl' namespace is not specified in the input (true or [false])" ,
311cecb4a16SMasatake YAMATO 	  .handleParameter = itclForceUseParamHandler,
312cecb4a16SMasatake YAMATO 	},
313cecb4a16SMasatake YAMATO };
314cecb4a16SMasatake YAMATO 
ITclParser(void)3156ae73029SMasatake YAMATO extern parserDefinition* ITclParser (void)
3166ae73029SMasatake YAMATO {
3176ae73029SMasatake YAMATO 	static const char *const extensions [] = { "itcl", NULL };
3186ae73029SMasatake YAMATO 	parserDefinition* const def = parserNew("ITcl");
3196ae73029SMasatake YAMATO 
3206ae73029SMasatake YAMATO 	static parserDependency dependencies [] = {
3216ae73029SMasatake YAMATO 		[0] = { DEPTYPE_SUBPARSER, "Tcl", &itclSubparser },
3226ae73029SMasatake YAMATO 	};
3236ae73029SMasatake YAMATO 
3246ae73029SMasatake YAMATO 	def->dependencies = dependencies;
3256ae73029SMasatake YAMATO 	def->dependencyCount = ARRAY_SIZE (dependencies);
3266ae73029SMasatake YAMATO 
3276ae73029SMasatake YAMATO 	def->kindTable = ITclKinds;
3286ae73029SMasatake YAMATO 	def->kindCount = ARRAY_SIZE(ITclKinds);
3296ae73029SMasatake YAMATO 
3306ae73029SMasatake YAMATO 	def->extensions = extensions;
3316ff1e862SMasatake YAMATO 	def->parser = findITclTags;
3326b1a862eSMasatake YAMATO 	def->useCork = CORK_QUEUE;
33394e60171SMasatake YAMATO 	def->requestAutomaticFQTag = true;
33494e60171SMasatake YAMATO 
33594e60171SMasatake YAMATO 	def->keywordTable = ITclKeywordTable;
33694e60171SMasatake YAMATO 	def->keywordCount = ARRAY_SIZE (ITclKeywordTable);
3376ae73029SMasatake YAMATO 
338cecb4a16SMasatake YAMATO 	def->parameterHandlerTable = ItclParameterHandlerTable;
339cecb4a16SMasatake YAMATO 	def->parameterHandlerCount = ARRAY_SIZE(ItclParameterHandlerTable);
340cecb4a16SMasatake YAMATO 
3416ae73029SMasatake YAMATO 	return def;
3426ae73029SMasatake YAMATO }
343