Autoit: drop $ from variable names
[geany-mirror.git] / ctags / parsers / autoit.c
blob56df9a0974805f0de28b04f01c88cfdb2bf731b1
1 /*
2 * Copyright (c) 2017, Alexey Olenich
3 * Copyright (c) 2018, Colomban Wendling <colomban@geany.org>
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.
8 * This module contains functions for generating tags for AutoIt functions.
9 * Homepage https://www.autoitscript.com/site/autoit/
10 * Online Documentation https://www.autoitscript.com/autoit3/docs/
14 * INCLUDE FILES
16 #include "general.h" /* must always come first */
18 #include <string.h>
20 #include "parse.h"
21 #include "entry.h"
22 #include "nestlevel.h"
23 #include "read.h"
24 #include "routines.h"
25 #include "vstring.h"
28 * DATA DEFINITIONS
30 typedef enum {
31 K_FUNCTION,
32 K_REGION,
33 K_GLOBALVAR,
34 K_LOCALVAR,
35 K_SCRIPT,
36 } AutoItKind;
38 typedef enum {
39 R_INCLUDE_SYSTEM,
40 R_INCLUDE_LOCAL,
41 } AutoItIncludeRole;
43 typedef enum {
44 F_PROPERTIES,
45 } AutoItField;
47 static roleDefinition AutoItIncludeRoles [] = {
48 { true, "system", "system include" },
49 { true, "local", "local include" },
52 static kindDefinition AutoItKinds [] = {
53 { true, 'f', "func", "functions" },
54 { true, 'r', "region", "regions" },
55 { true, 'g', "global", "global variables" },
56 { true, 'l', "local", "local variables" },
57 { true, 'S', "script", "included scripts",
58 .referenceOnly = true, ATTACH_ROLES (AutoItIncludeRoles) },
61 static fieldDefinition AutoItFields [] = {
63 .name = "properties",
64 .description = "properties (static, volatile, ...)",
65 .enabled = false,
70 * FUNCTION DEFINITIONS
73 /* it's unclear what *is* an identifier character, so maybe we're too strict */
74 static bool isIdentChar (int c)
76 return isalnum (c) || c == '_';
79 static bool match (const unsigned char *line, const char *word,
80 const unsigned char **positionAfter)
82 size_t len = strlen (word);
83 bool matched = (strncasecmp ((const char*) line, word, len) == 0 &&
84 ! isIdentChar (line[len]));
86 if (matched && positionAfter)
87 *positionAfter = line + len;
89 return matched;
92 static int makeAutoItTag (const NestingLevels *const nls,
93 const vString* const name,
94 const int kindIndex,
95 const vString *const signature)
97 int r = CORK_NIL;
99 if (isInputLanguageKindEnabled(kindIndex) && name != NULL && vStringLength (name) > 0)
101 NestingLevel *nl = nestingLevelsGetCurrent (nls);
102 tagEntryInfo e;
104 initTagEntry (&e, vStringValue (name), kindIndex);
106 if (nl)
107 e.extensionFields.scopeIndex = nl->corkIndex;
108 if (signature)
109 e.extensionFields.signature = vStringValue (signature);
111 r = makeTagEntry (&e);
114 return r;
117 static int makeSimpleAutoItTag (const NestingLevels *const nls,
118 const vString* const name,
119 const int kindIndex)
121 return makeAutoItTag (nls, name, kindIndex, NULL);
124 static void setEndLine (const NestingLevels *const nls)
126 NestingLevel *nl = nestingLevelsGetCurrent (nls);
127 tagEntryInfo *entry;
129 if (nl && (entry = getEntryInCorkQueue (nl->corkIndex)) != NULL)
130 entry->extensionFields.endLine = getInputLineNumber ();
133 static void skipSpaces (const unsigned char **p)
135 while (isspace ((int) **p))
136 ++(*p);
139 /* parses after a "func" keyword */
140 static int parseFunc (const unsigned char *p, NestingLevels *nls)
142 int k = CORK_NIL;
143 vString *name = vStringNew ();
145 skipSpaces (&p);
146 while (isIdentChar ((int) *p))
148 vStringPut (name, (int) *p);
149 ++p;
151 skipSpaces (&p);
152 if (*p == '(' && (vStringLength (name) > 0))
154 vString *signature = vStringNew ();
157 vStringPut (signature, (int) *p);
158 while (*p != ')' && *p++);
160 k = makeAutoItTag (nls, name, K_FUNCTION, signature);
161 nestingLevelsPush (nls, k);
162 vStringDelete (signature);
165 vStringDelete (name);
167 return k;
170 static void findAutoItTags (void)
172 vString *name = vStringNew ();
173 const unsigned char *line;
174 NestingLevels *nls = nestingLevelsNew (0);
175 unsigned int commentDepth = 0;
177 while ((line = readLineFromInputFile ()) != NULL)
179 const unsigned char* p = line;
180 if (p [0] == '#')
182 p++;
183 if (match (p, "cs", NULL) || match (p, "comments-start", NULL))
184 commentDepth++;
185 else if (commentDepth > 0)
187 if (match (p, "ce", NULL) || match (p, "comments-end", NULL))
188 commentDepth--;
190 else if (match (p, "region", &p))
192 skipSpaces (&p);
193 while (*p != '\0')
195 vStringPut (name, (int) *p);
196 ++p;
199 if (vStringLength(name) > 0)
201 int k = makeSimpleAutoItTag (nls, name, K_REGION);
202 nestingLevelsPush (nls, k);
203 vStringClear (name);
206 else if (nls->n > 0 && match (p, "endregion", NULL))
208 setEndLine (nls);
209 nestingLevelsPop (nls);
211 else if (match (p, "include", &p))
213 skipSpaces (&p);
214 if (*p == '<' || *p == '"')
216 const AutoItIncludeRole role = (*p == '<')
217 ? R_INCLUDE_SYSTEM
218 : R_INCLUDE_LOCAL;
220 ++p;
221 while (*p != '\0' && *p != '>' && *p != '"')
223 vStringPut (name, (int) *p);
224 ++p;
226 if (vStringLength(name) > 0)
228 makeSimpleRefTag (name, K_SCRIPT, role);
229 vStringClear (name);
234 else if (commentDepth == 0)
236 bool isGlobal = false;
237 bool isStatic = false;
239 /* skip white space */
240 skipSpaces (&p);
241 if (*p == ';')
242 /* ignore single-line comments */;
243 else if (match (p, "volatile", &p))
245 skipSpaces (&p);
246 if (match (p, "func", &p))
248 int k = parseFunc (p, nls);
249 if (k != CORK_NIL)
250 attachParserFieldToCorkEntry (k, AutoItFields[F_PROPERTIES].ftype, "volatile");
253 else if (match (p, "func", &p))
254 parseFunc (p, nls);
255 else if (nls->n > 0 && match (p, "endfunc", NULL))
257 setEndLine (nls);
258 nestingLevelsPop (nls);
260 else if ((isStatic = match (p, "static", &p)) ||
261 (isGlobal = match (p, "global", &p)) ||
262 match (p, "local", &p))
265 * variable-identifier ::= "$[a-zA-Z_0-9]+"
266 * scope-modifier ::= "Local" | "Global"
267 * variable-declaration ::= "Static" [scope-modifier] variable-identifier
268 * scope-modifier ["Static" | "Const"] variable-identifier
270 skipSpaces (&p);
271 if (isStatic)
273 /* skip optional modifiers */
274 if ((isGlobal = match (p, "global", &p)) ||
275 match (p, "local", &p))
277 skipSpaces (&p);
280 else if ((isStatic = match (p, "static", &p)))
281 skipSpaces (&p);
282 else if (match (p, "const", &p))
283 skipSpaces (&p);
284 if (*p == '$')
286 p++;
287 while (isIdentChar ((int) *p))
289 vStringPut (name, (int) *p);
290 ++p;
292 if (vStringLength(name) > 0)
294 int k = makeSimpleAutoItTag (nls, name, isGlobal ? K_GLOBALVAR : K_LOCALVAR);
295 if (k != CORK_NIL && isStatic)
296 attachParserFieldToCorkEntry (k, AutoItFields[F_PROPERTIES].ftype, "static");
298 vStringClear (name);
303 vStringDelete (name);
304 nestingLevelsFree (nls);
307 parserDefinition *AutoItParser (void)
309 static char const *extensions[] = { "au3", "AU3", "aU3", "Au3", NULL };
310 parserDefinition* def = parserNew ("AutoIt");
311 def->kindTable = AutoItKinds;
312 def->kindCount = ARRAY_SIZE (AutoItKinds);
313 def->fieldTable = AutoItFields;
314 def->fieldCount = ARRAY_SIZE (AutoItFields);
315 def->extensions = extensions;
316 def->parser = findAutoItTags;
317 def->useCork = CORK_QUEUE;
318 return def;