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/
16 #include "general.h" /* must always come first */
22 #include "nestlevel.h"
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
[] = {
64 .description
= "properties (static, volatile, ...)",
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
;
92 static int makeAutoItTag (const NestingLevels
*const nls
,
93 const vString
* const name
,
95 const vString
*const signature
)
99 if (isInputLanguageKindEnabled(kindIndex
) && name
!= NULL
&& vStringLength (name
) > 0)
101 NestingLevel
*nl
= nestingLevelsGetCurrent (nls
);
104 initTagEntry (&e
, vStringValue (name
), kindIndex
);
107 e
.extensionFields
.scopeIndex
= nl
->corkIndex
;
109 e
.extensionFields
.signature
= vStringValue (signature
);
111 r
= makeTagEntry (&e
);
117 static int makeSimpleAutoItTag (const NestingLevels
*const nls
,
118 const vString
* const name
,
121 return makeAutoItTag (nls
, name
, kindIndex
, NULL
);
124 static void setEndLine (const NestingLevels
*const nls
)
126 NestingLevel
*nl
= nestingLevelsGetCurrent (nls
);
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
))
139 /* parses after a "func" keyword */
140 static int parseFunc (const unsigned char *p
, NestingLevels
*nls
)
143 vString
*name
= vStringNew ();
146 while (isIdentChar ((int) *p
))
148 vStringPut (name
, (int) *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
);
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
;
183 if (match (p
, "cs", NULL
) || match (p
, "comments-start", NULL
))
185 else if (commentDepth
> 0)
187 if (match (p
, "ce", NULL
) || match (p
, "comments-end", NULL
))
190 else if (match (p
, "region", &p
))
195 vStringPut (name
, (int) *p
);
199 if (vStringLength(name
) > 0)
201 int k
= makeSimpleAutoItTag (nls
, name
, K_REGION
);
202 nestingLevelsPush (nls
, k
);
206 else if (nls
->n
> 0 && match (p
, "endregion", NULL
))
209 nestingLevelsPop (nls
);
211 else if (match (p
, "include", &p
))
214 if (*p
== '<' || *p
== '"')
216 const AutoItIncludeRole role
= (*p
== '<')
221 while (*p
!= '\0' && *p
!= '>' && *p
!= '"')
223 vStringPut (name
, (int) *p
);
226 if (vStringLength(name
) > 0)
228 makeSimpleRefTag (name
, K_SCRIPT
, role
);
234 else if (commentDepth
== 0)
236 bool isGlobal
= false;
237 bool isStatic
= false;
239 /* skip white space */
242 /* ignore single-line comments */;
243 else if (match (p
, "volatile", &p
))
246 if (match (p
, "func", &p
))
248 int k
= parseFunc (p
, nls
);
250 attachParserFieldToCorkEntry (k
, AutoItFields
[F_PROPERTIES
].ftype
, "volatile");
253 else if (match (p
, "func", &p
))
255 else if (nls
->n
> 0 && match (p
, "endfunc", NULL
))
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
273 /* skip optional modifiers */
274 if ((isGlobal
= match (p
, "global", &p
)) ||
275 match (p
, "local", &p
))
280 else if ((isStatic
= match (p
, "static", &p
)))
282 else if (match (p
, "const", &p
))
287 while (isIdentChar ((int) *p
))
289 vStringPut (name
, (int) *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");
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
;