xref: /Universal-ctags/parsers/autoit.c (revision 6b1a862e526d5017f9f212a321f59d67c859d521)
1b00f4969SSkif-off /*
2b00f4969SSkif-off *   Copyright (c) 2017, Alexey Olenich
30218c247SColomban Wendling *   Copyright (c) 2018, Colomban Wendling <colomban@geany.org>
4b00f4969SSkif-off *
5b00f4969SSkif-off *   This source code is released for free distribution under the terms of the
6b00f4969SSkif-off *   GNU General Public License version 2 or (at your option) any later version.
7b00f4969SSkif-off *
8b00f4969SSkif-off *   This module contains functions for generating tags for AutoIt functions.
9b00f4969SSkif-off *   Homepage             https://www.autoitscript.com/site/autoit/
10b00f4969SSkif-off *   Online Documentation https://www.autoitscript.com/autoit3/docs/
11b00f4969SSkif-off */
12b00f4969SSkif-off 
13b00f4969SSkif-off /*
14b00f4969SSkif-off *   INCLUDE FILES
15b00f4969SSkif-off */
16b00f4969SSkif-off #include "general.h"  /* must always come first */
17b00f4969SSkif-off 
18b00f4969SSkif-off #include <string.h>
19b00f4969SSkif-off 
20b00f4969SSkif-off #include "parse.h"
2114781660SMasatake YAMATO #include "entry.h"
22ff1b419eSMasatake YAMATO #include "nestlevel.h"
23b00f4969SSkif-off #include "read.h"
24b00f4969SSkif-off #include "routines.h"
25b00f4969SSkif-off #include "vstring.h"
26b00f4969SSkif-off 
27b00f4969SSkif-off /*
28b00f4969SSkif-off *   DATA DEFINITIONS
29b00f4969SSkif-off */
30b00f4969SSkif-off typedef enum {
31b00f4969SSkif-off 	K_FUNCTION,
3232ddb301SColomban Wendling 	K_REGION,
3332ddb301SColomban Wendling 	K_GLOBALVAR,
3432ddb301SColomban Wendling 	K_LOCALVAR,
35c396ae83SColomban Wendling 	K_SCRIPT,
36b00f4969SSkif-off } AutoItKind;
37b00f4969SSkif-off 
38c396ae83SColomban Wendling typedef enum {
39c396ae83SColomban Wendling 	R_INCLUDE_SYSTEM,
40c396ae83SColomban Wendling 	R_INCLUDE_LOCAL,
41c396ae83SColomban Wendling } AutoItIncludeRole;
42c396ae83SColomban Wendling 
43849f2aabSColomban Wendling typedef enum {
44849f2aabSColomban Wendling 	F_PROPERTIES,
45849f2aabSColomban Wendling } AutoItField;
46849f2aabSColomban Wendling 
47c396ae83SColomban Wendling static roleDefinition AutoItIncludeRoles [] = {
48c396ae83SColomban Wendling 	{ true, "system", "system include" },
49c396ae83SColomban Wendling 	{ true, "local", "local include" },
50c396ae83SColomban Wendling };
51c396ae83SColomban Wendling 
52b00f4969SSkif-off static kindDefinition AutoItKinds [] = {
53b00f4969SSkif-off 	{ true, 'f', "func", "functions" },
5432ddb301SColomban Wendling 	{ true, 'r', "region", "regions" },
5532ddb301SColomban Wendling 	{ true, 'g', "global", "global variables" },
5632ddb301SColomban Wendling 	{ true, 'l', "local", "local variables" },
57c396ae83SColomban Wendling 	{ true, 'S', "script", "included scripts",
58c396ae83SColomban Wendling 	  .referenceOnly = true, ATTACH_ROLES (AutoItIncludeRoles) },
59b00f4969SSkif-off };
60b00f4969SSkif-off 
61849f2aabSColomban Wendling static fieldDefinition AutoItFields [] = {
62849f2aabSColomban Wendling 	{
63849f2aabSColomban Wendling 		.name = "properties",
64849f2aabSColomban Wendling 		.description = "properties (static, volatile, ...)",
65849f2aabSColomban Wendling 		.enabled = false,
66849f2aabSColomban Wendling 	},
67849f2aabSColomban Wendling };
68849f2aabSColomban Wendling 
69b00f4969SSkif-off /*
70b00f4969SSkif-off *   FUNCTION DEFINITIONS
71b00f4969SSkif-off */
7213a55800SColomban Wendling 
7313a55800SColomban Wendling /* it's unclear what *is* an identifier character, so maybe we're too strict */
isIdentChar(int c)7413a55800SColomban Wendling static bool isIdentChar (int c)
7513a55800SColomban Wendling {
7613a55800SColomban Wendling 	return isalnum (c) || c == '_';
7713a55800SColomban Wendling }
7813a55800SColomban Wendling 
match(const unsigned char * line,const char * word,const unsigned char ** positionAfter)79647d24b2SColomban Wendling static bool match (const unsigned char *line, const char *word,
80647d24b2SColomban Wendling                    const unsigned char **positionAfter)
817d488265SColomban Wendling {
827d488265SColomban Wendling 	size_t len = strlen (word);
83647d24b2SColomban Wendling 	bool matched = (strncasecmp ((const char*) line, word, len) == 0 &&
8413a55800SColomban Wendling 	                ! isIdentChar (line[len]));
85647d24b2SColomban Wendling 
86647d24b2SColomban Wendling 	if (matched && positionAfter)
87647d24b2SColomban Wendling 		*positionAfter = line + len;
88647d24b2SColomban Wendling 
89647d24b2SColomban Wendling 	return matched;
907d488265SColomban Wendling }
917d488265SColomban Wendling 
makeAutoItTag(const NestingLevels * const nls,const vString * const name,const int kindIndex,const vString * const signature)92069d5c02SColomban Wendling static int makeAutoItTag (const NestingLevels *const nls,
93479bcebfSColomban Wendling                           const vString* const name,
94069d5c02SColomban Wendling                           const int kindIndex,
95069d5c02SColomban Wendling                           const vString *const signature)
96479bcebfSColomban Wendling {
97479bcebfSColomban Wendling 	int r = CORK_NIL;
98479bcebfSColomban Wendling 
99479bcebfSColomban Wendling 	if (isInputLanguageKindEnabled(kindIndex) && name != NULL && vStringLength (name) > 0)
100479bcebfSColomban Wendling 	{
101479bcebfSColomban Wendling 		NestingLevel *nl = nestingLevelsGetCurrent (nls);
102479bcebfSColomban Wendling 		tagEntryInfo e;
103479bcebfSColomban Wendling 
104479bcebfSColomban Wendling 		initTagEntry (&e, vStringValue (name), kindIndex);
105479bcebfSColomban Wendling 
106479bcebfSColomban Wendling 		if (nl)
107479bcebfSColomban Wendling 			e.extensionFields.scopeIndex = nl->corkIndex;
108069d5c02SColomban Wendling 		if (signature)
109069d5c02SColomban Wendling 			e.extensionFields.signature = vStringValue (signature);
110479bcebfSColomban Wendling 
111479bcebfSColomban Wendling 		r = makeTagEntry (&e);
112479bcebfSColomban Wendling 	}
113479bcebfSColomban Wendling 
114479bcebfSColomban Wendling 	return r;
115479bcebfSColomban Wendling }
116479bcebfSColomban Wendling 
makeSimpleAutoItTag(const NestingLevels * const nls,const vString * const name,const int kindIndex)117069d5c02SColomban Wendling static int makeSimpleAutoItTag (const NestingLevels *const nls,
118069d5c02SColomban Wendling                                 const vString* const name,
119069d5c02SColomban Wendling                                 const int kindIndex)
120069d5c02SColomban Wendling {
121069d5c02SColomban Wendling 	return makeAutoItTag (nls, name, kindIndex, NULL);
122069d5c02SColomban Wendling }
123069d5c02SColomban Wendling 
setEndLine(const NestingLevels * const nls)124e77a4c9aSColomban Wendling static void setEndLine (const NestingLevels *const nls)
125e77a4c9aSColomban Wendling {
126e77a4c9aSColomban Wendling 	NestingLevel *nl = nestingLevelsGetCurrent (nls);
127e77a4c9aSColomban Wendling 	tagEntryInfo *entry;
128e77a4c9aSColomban Wendling 
129e77a4c9aSColomban Wendling 	if (nl && (entry = getEntryInCorkQueue (nl->corkIndex)) != NULL)
130e77a4c9aSColomban Wendling 		entry->extensionFields.endLine = getInputLineNumber ();
131e77a4c9aSColomban Wendling }
132e77a4c9aSColomban Wendling 
skipSpaces(const unsigned char ** p)133b2c54656SColomban Wendling static void skipSpaces (const unsigned char **p)
134b2c54656SColomban Wendling {
135b2c54656SColomban Wendling 	while (isspace ((int) **p))
136b2c54656SColomban Wendling 		++(*p);
137b2c54656SColomban Wendling }
138b2c54656SColomban Wendling 
1391f540ed9SColomban Wendling /* parses after a "func" keyword */
parseFunc(const unsigned char * p,NestingLevels * nls)140849f2aabSColomban Wendling static int parseFunc (const unsigned char *p, NestingLevels *nls)
1411f540ed9SColomban Wendling {
142849f2aabSColomban Wendling 	int k = CORK_NIL;
1431f540ed9SColomban Wendling 	vString *name = vStringNew ();
1441f540ed9SColomban Wendling 
1451f540ed9SColomban Wendling 	skipSpaces (&p);
1461f540ed9SColomban Wendling 	while (isIdentChar ((int) *p))
1471f540ed9SColomban Wendling 	{
1481f540ed9SColomban Wendling 		vStringPut (name, (int) *p);
1491f540ed9SColomban Wendling 		++p;
1501f540ed9SColomban Wendling 	}
1511f540ed9SColomban Wendling 	skipSpaces (&p);
1521f540ed9SColomban Wendling 	if (*p == '(' && (vStringLength (name) > 0))
1531f540ed9SColomban Wendling 	{
1541f540ed9SColomban Wendling 		vString *signature = vStringNew ();
1551f540ed9SColomban Wendling 
1561f540ed9SColomban Wendling 		do
1571f540ed9SColomban Wendling 			vStringPut (signature, (int) *p);
1581f540ed9SColomban Wendling 		while (*p != ')' && *p++);
1591f540ed9SColomban Wendling 
1601f540ed9SColomban Wendling 		k = makeAutoItTag (nls, name, K_FUNCTION, signature);
1611f540ed9SColomban Wendling 		nestingLevelsPush (nls, k);
1621f540ed9SColomban Wendling 		vStringDelete (signature);
1631f540ed9SColomban Wendling 	}
1641f540ed9SColomban Wendling 
1651f540ed9SColomban Wendling 	vStringDelete (name);
166849f2aabSColomban Wendling 
167849f2aabSColomban Wendling 	return k;
1681f540ed9SColomban Wendling }
1691f540ed9SColomban Wendling 
findAutoItTags(void)170b00f4969SSkif-off static void findAutoItTags (void)
171b00f4969SSkif-off {
172b00f4969SSkif-off 	vString *name = vStringNew ();
173b00f4969SSkif-off 	const unsigned char *line;
174479bcebfSColomban Wendling 	NestingLevels *nls = nestingLevelsNew (0);
175e1b1e867SColomban Wendling 	unsigned int commentDepth = 0;
176b00f4969SSkif-off 
177b00f4969SSkif-off 	while ((line = readLineFromInputFile ()) != NULL)
178b00f4969SSkif-off 	{
179b00f4969SSkif-off 		const unsigned char* p = line;
180b00f4969SSkif-off 		if (p [0] == '#')
181b00f4969SSkif-off 		{
1827d488265SColomban Wendling 			p++;
183647d24b2SColomban Wendling 			if (match (p, "cs", NULL) || match (p, "comments-start", NULL))
184e1b1e867SColomban Wendling 				commentDepth++;
185e1b1e867SColomban Wendling 			else if (commentDepth > 0)
186e1b1e867SColomban Wendling 			{
187647d24b2SColomban Wendling 				if (match (p, "ce", NULL) || match (p, "comments-end", NULL))
188e1b1e867SColomban Wendling 					commentDepth--;
189e1b1e867SColomban Wendling 			}
190647d24b2SColomban Wendling 			else if (match (p, "region", &p))
191b00f4969SSkif-off 			{
192b2c54656SColomban Wendling 				skipSpaces (&p);
193b00f4969SSkif-off 				while (*p != '\0')
194b00f4969SSkif-off 				{
195b00f4969SSkif-off 					vStringPut (name, (int) *p);
196b00f4969SSkif-off 					++p;
197b00f4969SSkif-off 				}
198b00f4969SSkif-off 
199b00f4969SSkif-off 				if (vStringLength(name) > 0)
200b00f4969SSkif-off 				{
201479bcebfSColomban Wendling 					int k = makeSimpleAutoItTag (nls, name, K_REGION);
202479bcebfSColomban Wendling 					nestingLevelsPush (nls, k);
203b00f4969SSkif-off 					vStringClear (name);
204b00f4969SSkif-off 				}
205b00f4969SSkif-off 			}
206647d24b2SColomban Wendling 			else if (nls->n > 0 && match (p, "endregion", NULL))
207e77a4c9aSColomban Wendling 			{
208e77a4c9aSColomban Wendling 				setEndLine (nls);
209479bcebfSColomban Wendling 				nestingLevelsPop (nls);
210e77a4c9aSColomban Wendling 			}
211647d24b2SColomban Wendling 			else if (match (p, "include", &p))
212c396ae83SColomban Wendling 			{
213b2c54656SColomban Wendling 				skipSpaces (&p);
214c396ae83SColomban Wendling 				if (*p == '<' || *p == '"')
215c396ae83SColomban Wendling 				{
216c396ae83SColomban Wendling 					const AutoItIncludeRole role = (*p == '<')
217c396ae83SColomban Wendling 						? R_INCLUDE_SYSTEM
218c396ae83SColomban Wendling 						: R_INCLUDE_LOCAL;
219c396ae83SColomban Wendling 
220c396ae83SColomban Wendling 					++p;
221c396ae83SColomban Wendling 					while (*p != '\0' && *p != '>' && *p != '"')
222c396ae83SColomban Wendling 					{
223c396ae83SColomban Wendling 						vStringPut (name, (int) *p);
224c396ae83SColomban Wendling 						++p;
225c396ae83SColomban Wendling 					}
226c396ae83SColomban Wendling 					if (vStringLength(name) > 0)
227c396ae83SColomban Wendling 					{
228c396ae83SColomban Wendling 						makeSimpleRefTag (name, K_SCRIPT, role);
229c396ae83SColomban Wendling 						vStringClear (name);
230c396ae83SColomban Wendling 					}
231c396ae83SColomban Wendling 				}
232c396ae83SColomban Wendling 			}
233b00f4969SSkif-off 		}
234e1b1e867SColomban Wendling 		else if (commentDepth == 0)
235b00f4969SSkif-off 		{
23632ddb301SColomban Wendling 			bool isGlobal = false;
237a507ec20SColomban Wendling 			bool isStatic = false;
23832ddb301SColomban Wendling 
239b00f4969SSkif-off 			/* skip white space */
240b2c54656SColomban Wendling 			skipSpaces (&p);
241f4e01995SColomban Wendling 			if (*p == ';')
242f4e01995SColomban Wendling 				/* ignore single-line comments */;
2431f540ed9SColomban Wendling 			else if (match (p, "volatile", &p))
2441f540ed9SColomban Wendling 			{
2451f540ed9SColomban Wendling 				skipSpaces (&p);
2461f540ed9SColomban Wendling 				if (match (p, "func", &p))
247849f2aabSColomban Wendling 				{
248849f2aabSColomban Wendling 					int k = parseFunc (p, nls);
249849f2aabSColomban Wendling 					if (k != CORK_NIL)
250849f2aabSColomban Wendling 						attachParserFieldToCorkEntry (k, AutoItFields[F_PROPERTIES].ftype, "volatile");
251849f2aabSColomban Wendling 				}
2521f540ed9SColomban Wendling 			}
253647d24b2SColomban Wendling 			else if (match (p, "func", &p))
2541f540ed9SColomban Wendling 				parseFunc (p, nls);
255647d24b2SColomban Wendling 			else if (nls->n > 0 && match (p, "endfunc", NULL))
256e77a4c9aSColomban Wendling 			{
257e77a4c9aSColomban Wendling 				setEndLine (nls);
258479bcebfSColomban Wendling 				nestingLevelsPop (nls);
259e77a4c9aSColomban Wendling 			}
260a507ec20SColomban Wendling 			else if ((isStatic = match (p, "static", &p)) ||
261a507ec20SColomban Wendling 			         (isGlobal = match (p, "global", &p)) ||
262a507ec20SColomban Wendling 			         match (p, "local", &p))
263a507ec20SColomban Wendling 			{
264a507ec20SColomban Wendling 				/*
265a507ec20SColomban Wendling 				 * variable-identifier ::= "$[a-zA-Z_0-9]+"
266a507ec20SColomban Wendling 				 * scope-modifier ::= "Local" | "Global"
267a507ec20SColomban Wendling 				 * variable-declaration ::= "Static" [scope-modifier] variable-identifier
268a507ec20SColomban Wendling 				 *                          scope-modifier ["Static" | "Const"] variable-identifier
269a507ec20SColomban Wendling 				 */
270a507ec20SColomban Wendling 				skipSpaces (&p);
271a507ec20SColomban Wendling 				if (isStatic)
272a507ec20SColomban Wendling 				{
273a507ec20SColomban Wendling 					/* skip optional modifiers */
274a507ec20SColomban Wendling 					if ((isGlobal = match (p, "global", &p)) ||
275647d24b2SColomban Wendling 					    match (p, "local", &p))
27632ddb301SColomban Wendling 					{
277b2c54656SColomban Wendling 						skipSpaces (&p);
278a507ec20SColomban Wendling 					}
279a507ec20SColomban Wendling 				}
280a507ec20SColomban Wendling 				else if ((isStatic = match (p, "static", &p)))
281a507ec20SColomban Wendling 					skipSpaces (&p);
282a507ec20SColomban Wendling 				else if (match (p, "const", &p))
283b2c54656SColomban Wendling 					skipSpaces (&p);
28432ddb301SColomban Wendling 				if (*p == '$')
28532ddb301SColomban Wendling 				{
28632ddb301SColomban Wendling 					vStringPut (name, (int) *p++);
28713a55800SColomban Wendling 					while (isIdentChar ((int) *p))
28832ddb301SColomban Wendling 					{
28932ddb301SColomban Wendling 						vStringPut (name, (int) *p);
29032ddb301SColomban Wendling 						++p;
29132ddb301SColomban Wendling 					}
29232ddb301SColomban Wendling 					if (vStringLength(name) > 0)
293849f2aabSColomban Wendling 					{
294849f2aabSColomban Wendling 						int k = makeSimpleAutoItTag (nls, name, isGlobal ? K_GLOBALVAR : K_LOCALVAR);
295849f2aabSColomban Wendling 						if (k != CORK_NIL && isStatic)
296849f2aabSColomban Wendling 							attachParserFieldToCorkEntry (k, AutoItFields[F_PROPERTIES].ftype, "static");
297849f2aabSColomban Wendling 					}
29832ddb301SColomban Wendling 					vStringClear (name);
29932ddb301SColomban Wendling 				}
30032ddb301SColomban Wendling 			}
301b00f4969SSkif-off 		}
302b00f4969SSkif-off 	}
303b00f4969SSkif-off 	vStringDelete (name);
304479bcebfSColomban Wendling 	nestingLevelsFree (nls);
305b00f4969SSkif-off }
306b00f4969SSkif-off 
AutoItParser(void)307b00f4969SSkif-off parserDefinition *AutoItParser (void)
308b00f4969SSkif-off {
309b00f4969SSkif-off 	static char const *extensions[] = { "au3", "AU3", "aU3", "Au3", NULL };
310b00f4969SSkif-off 	parserDefinition* def = parserNew ("AutoIt");
311b00f4969SSkif-off 	def->kindTable      = AutoItKinds;
312b00f4969SSkif-off 	def->kindCount  = ARRAY_SIZE (AutoItKinds);
313849f2aabSColomban Wendling 	def->fieldTable = AutoItFields;
314849f2aabSColomban Wendling 	def->fieldCount = ARRAY_SIZE (AutoItFields);
315b00f4969SSkif-off 	def->extensions = extensions;
316b00f4969SSkif-off 	def->parser     = findAutoItTags;
317*6b1a862eSMasatake YAMATO 	def->useCork    = CORK_QUEUE;
318b00f4969SSkif-off 	return def;
319b00f4969SSkif-off }
320