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