xref: /Universal-ctags/parsers/tcloo.c (revision 0d95841219d1bdd1e1dfef5488de2ca8c080f09e)
1 /*
2 *   Copyright (c) 2017, Masatake YAMATO
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 */
8 
9 #include "general.h"  /* must always come first */
10 #include "tcl.h"
11 #include "param.h"
12 #include "parse.h"
13 #include "entry.h"
14 #include "tokeninfo.h"
15 
16 #include <string.h>
17 
18 
19 struct tclooSubparser {
20 	tclSubparser tcl;
21 	bool foundTclOONamespaceImported;
22 };
23 
24 static scopeSeparator TclOOGenericSeparators [] = {
25 	{ KIND_WILDCARD_INDEX, "::" },
26 };
27 
28 enum TclOOKind {
29 	K_CLASS,
30 	K_METHOD,
31 };
32 
33 static kindDefinition TclOOKinds[] = {
34 	{ true, 'c', "class", "classes" },
35 	{ true, 'm', "method", "methods",
36 	  ATTACH_SEPARATORS(TclOOGenericSeparators) },
37 };
38 
39 static bool tclooForceUse;
40 
parseMethod(tokenInfo * token,int owner)41 static void parseMethod (tokenInfo *token, int owner)
42 {
43 	tokenRead (token);
44 	if (tokenIsType (token, TCL_IDENTIFIER))
45 	{
46 		tagEntryInfo e;
47 
48 		initTagEntry(&e, tokenString (token), K_METHOD);
49 		e.extensionFields.scopeIndex = owner;
50 		makeTagEntry (&e);
51 	}
52 	skipToEndOfTclCmdline (token);
53 }
54 
parseSuperclass(tokenInfo * token,int this_class)55 static void parseSuperclass (tokenInfo *token, int this_class)
56 {
57 	tokenRead (token);
58 	if (tokenIsType (token, TCL_IDENTIFIER))
59 	{
60 		tagEntryInfo *e = getEntryInCorkQueue(this_class);
61 
62 		if (e)
63 		{
64 			if (e->extensionFields.inheritance)
65 			{   /* superclass is used twice in a class. */
66 				eFree ((void *)e->extensionFields.inheritance);
67 			}
68 			e->extensionFields.inheritance = eStrdup(tokenString(token));
69 		}
70 	}
71 	skipToEndOfTclCmdline (token);
72 }
73 
parseClass(tclSubparser * s CTAGS_ATTR_UNUSED,int parentIndex,void * pstate)74 static int parseClass (tclSubparser *s CTAGS_ATTR_UNUSED, int parentIndex,
75 					   void *pstate)
76 {
77 	tokenInfo *token = newTclToken (pstate);
78 	int r = CORK_NIL;
79 
80 	tokenRead (token);
81 	if (tokenIsType (token, TCL_IDENTIFIER)
82 		&& (strcmp(tokenString(token), "create") == 0))
83 	{
84 		tokenRead (token);
85 		if (tokenIsType (token, TCL_IDENTIFIER))
86 		{
87 			tagEntryInfo e;
88 
89 			initTagEntry(&e, tokenString (token), K_CLASS);
90 			e.extensionFields.scopeIndex = parentIndex;
91 			r = makeTagEntry (&e);
92 		}
93 
94 		if (tokenSkipToType (token, '{'))
95 		{
96 			do {
97 				tokenRead (token);
98 				if (tokenIsType (token, TCL_IDENTIFIER)
99 					|| tokenIsType (token, TCL_KEYWORD))
100 				{
101 					if (strcmp(tokenString(token), "method") == 0)
102 						parseMethod(token, r);
103 					else if (strcmp(tokenString(token), "superclass") == 0)
104 						parseSuperclass(token, r);
105 					else
106 						skipToEndOfTclCmdline (token);
107 				}
108 				else if (token->type == '}')
109 					break;
110 			} while (!tokenIsEOF(token));
111 		}
112 	}
113 
114 	skipToEndOfTclCmdline (token);
115 	tokenDelete(token);
116 	return r;
117 }
118 
commandNotify(tclSubparser * s,char * command,int parentIndex,void * pstate)119 static int commandNotify (tclSubparser *s, char *command,
120 						  int parentIndex, void *pstate)
121 {
122 	struct tclooSubparser *tcloo = (struct tclooSubparser *)s;
123 	int r = CORK_NIL;
124 
125 	if ((tcloo->foundTclOONamespaceImported
126 		 && (strcmp (command, "class") == 0))
127 		|| (strcmp (command, "oo::class") == 0))
128 		r = parseClass (s, parentIndex, pstate);
129 
130 	return r;
131 }
132 
namespaceImportNotify(tclSubparser * s,char * namespace,void * pstate CTAGS_ATTR_UNUSED)133 static void namespaceImportNotify (tclSubparser *s, char *namespace,
134 								   void *pstate CTAGS_ATTR_UNUSED)
135 {
136 	struct tclooSubparser *tcloo = (struct tclooSubparser *)s;
137 
138 	if (strcmp(namespace, "oo::*") == 0
139 		|| strcmp(namespace, "oo::class") == 0)
140 		tcloo->foundTclOONamespaceImported = true;
141 }
142 
inputStart(subparser * s)143 static void inputStart (subparser *s)
144 {
145 	struct tclooSubparser *tcloo = (struct tclooSubparser *)s;
146 
147 	tcloo->foundTclOONamespaceImported = tclooForceUse;
148 }
149 
150 static struct tclooSubparser tclooSubparser = {
151 	.tcl = {
152 		.subparser = {
153 			.direction = SUBPARSER_BI_DIRECTION,
154 			.inputStart = inputStart,
155 		},
156 		.commandNotify = commandNotify,
157 		.namespaceImportNotify = namespaceImportNotify,
158 	},
159 };
160 
findTclOOTags(void)161 static void findTclOOTags(void)
162 {
163 	scheduleRunningBaseparser (RUN_DEFAULT_SUBPARSERS);
164 }
165 
tclooForceUseParamHandler(const langType language CTAGS_ATTR_UNUSED,const char * name,const char * arg)166 static void tclooForceUseParamHandler (const langType language CTAGS_ATTR_UNUSED,
167 									  const char *name, const char *arg)
168 {
169 	tclooForceUse = paramParserBool (arg, tclooForceUse, name, "parameter");
170 }
171 
172 static parameterHandlerTable TclOOParameterHandlerTable [] = {
173 	{ .name = "forceUse",
174 	  .desc = "enable the parser even when `oo' namespace is not specified in the input (true or [false])" ,
175 	  .handleParameter = tclooForceUseParamHandler,
176 	},
177 };
178 
TclOOParser(void)179 extern parserDefinition* TclOOParser (void)
180 {
181 	parserDefinition* const def = parserNew("TclOO");
182 
183 	static parserDependency dependencies [] = {
184 		[0] = { DEPTYPE_SUBPARSER, "Tcl", &tclooSubparser },
185 	};
186 
187 	def->dependencies = dependencies;
188 	def->dependencyCount = ARRAY_SIZE (dependencies);
189 
190 	def->kindTable = TclOOKinds;
191 	def->kindCount = ARRAY_SIZE(TclOOKinds);
192 
193 	def->parser = findTclOOTags;
194 	def->useCork = CORK_QUEUE;
195 	def->requestAutomaticFQTag = true;
196 
197 	def->parameterHandlerTable = TclOOParameterHandlerTable;
198 	def->parameterHandlerCount = ARRAY_SIZE(TclOOParameterHandlerTable);
199 
200 	return def;
201 }
202