1ebbfee1eSDavid Yu Yang /*
2ebbfee1eSDavid Yu Yang * Copyright (c) 2000-2003, Darren Hiebert
3ebbfee1eSDavid Yu Yang * Copyright (c) 2014-2016, Colomban Wendling <ban@herbesfolles.org>
4ebbfee1eSDavid Yu Yang * Copyright (c) 2021, David Yang <davidyang6us@gmail.com>
5ebbfee1eSDavid Yu Yang *
6ebbfee1eSDavid Yu Yang * This source code is released for free distribution under the terms of the
7ebbfee1eSDavid Yu Yang * GNU General Public License version 2 or (at your option) any later version.
8ebbfee1eSDavid Yu Yang *
9ebbfee1eSDavid Yu Yang * This module contains functions for generating tags for GDScript language
10ebbfee1eSDavid Yu Yang * files. This module is derived from the Python module.
11ebbfee1eSDavid Yu Yang *
12ebbfee1eSDavid Yu Yang * GDScript language reference:
13ebbfee1eSDavid Yu Yang * https://docs.godotengine.org/en/latest/tutorials/scripting/gdscript/gdscript_basics.html
14ebbfee1eSDavid Yu Yang * https://docs.godotengine.org/en/stable/development/file_formats/gdscript_grammar.html#doc-gdscript-grammar
15ebbfee1eSDavid Yu Yang * https://godotengine.org/article/gdscript-progress-report-new-gdscript-now-merged
16ebbfee1eSDavid Yu Yang *
17ebbfee1eSDavid Yu Yang */
18ebbfee1eSDavid Yu Yang
19ebbfee1eSDavid Yu Yang #include "general.h" /* must always come first */
20ebbfee1eSDavid Yu Yang
21ebbfee1eSDavid Yu Yang #include <string.h>
22ebbfee1eSDavid Yu Yang
23ebbfee1eSDavid Yu Yang #include "entry.h"
24ebbfee1eSDavid Yu Yang #include "nestlevel.h"
25ebbfee1eSDavid Yu Yang #include "read.h"
26ebbfee1eSDavid Yu Yang #include "parse.h"
27ebbfee1eSDavid Yu Yang #include "vstring.h"
28ebbfee1eSDavid Yu Yang #include "keyword.h"
29ebbfee1eSDavid Yu Yang #include "routines.h"
30ebbfee1eSDavid Yu Yang #include "debug.h"
31ebbfee1eSDavid Yu Yang #include "xtag.h"
32ebbfee1eSDavid Yu Yang #include "objpool.h"
33ebbfee1eSDavid Yu Yang #include "strlist.h"
34ebbfee1eSDavid Yu Yang
35ebbfee1eSDavid Yu Yang #define isIdentifierChar(c) \
36ebbfee1eSDavid Yu Yang (isalnum (c) || (c) == '_' || (c) >= 0x80)
37ebbfee1eSDavid Yu Yang #define newToken() (objPoolGet (TokenPool))
38ebbfee1eSDavid Yu Yang #define deleteToken(t) (objPoolPut (TokenPool, (t)))
39ebbfee1eSDavid Yu Yang
40ebbfee1eSDavid Yu Yang enum {
41ebbfee1eSDavid Yu Yang KEYWORD_class,
42ebbfee1eSDavid Yu Yang KEYWORD_func,
43ebbfee1eSDavid Yu Yang KEYWORD_extends,
44ebbfee1eSDavid Yu Yang KEYWORD_pass,
45ebbfee1eSDavid Yu Yang KEYWORD_return,
46ebbfee1eSDavid Yu Yang KEYWORD_lambda,
47ebbfee1eSDavid Yu Yang KEYWORD_variable,
48ebbfee1eSDavid Yu Yang KEYWORD_const,
49ebbfee1eSDavid Yu Yang KEYWORD_enum,
50ebbfee1eSDavid Yu Yang KEYWORD_class_name,
51ebbfee1eSDavid Yu Yang KEYWORD_signal,
52ebbfee1eSDavid Yu Yang KEYWORD_modifier,
53ebbfee1eSDavid Yu Yang };
54ebbfee1eSDavid Yu Yang typedef int keywordId; /* to allow KEYWORD_NONE */
55ebbfee1eSDavid Yu Yang
56ebbfee1eSDavid Yu Yang typedef enum {
57ebbfee1eSDavid Yu Yang ACCESS_PRIVATE,
58ebbfee1eSDavid Yu Yang ACCESS_PROTECTED,
59ebbfee1eSDavid Yu Yang ACCESS_PUBLIC,
60ebbfee1eSDavid Yu Yang COUNT_ACCESS
61ebbfee1eSDavid Yu Yang } accessType;
62ebbfee1eSDavid Yu Yang
63ebbfee1eSDavid Yu Yang static const char *const GDScriptAccesses[COUNT_ACCESS] = {
64ebbfee1eSDavid Yu Yang "private",
65ebbfee1eSDavid Yu Yang "protected",
66ebbfee1eSDavid Yu Yang "public"
67ebbfee1eSDavid Yu Yang };
68ebbfee1eSDavid Yu Yang
69ebbfee1eSDavid Yu Yang typedef enum {
70ebbfee1eSDavid Yu Yang F_ANNOTATIONS,
71ebbfee1eSDavid Yu Yang COUNT_FIELD
72ebbfee1eSDavid Yu Yang } gdscriptField;
73ebbfee1eSDavid Yu Yang
74ebbfee1eSDavid Yu Yang static fieldDefinition GDScriptFields[COUNT_FIELD] = {
75ebbfee1eSDavid Yu Yang { .name = "annotations",
76ebbfee1eSDavid Yu Yang .description = "annotations on functions and variables",
77ebbfee1eSDavid Yu Yang .enabled = true },
78ebbfee1eSDavid Yu Yang };
79ebbfee1eSDavid Yu Yang
80ebbfee1eSDavid Yu Yang typedef enum {
81ebbfee1eSDavid Yu Yang K_CLASS,
82ebbfee1eSDavid Yu Yang K_METHOD,
83ebbfee1eSDavid Yu Yang K_VARIABLE,
84ebbfee1eSDavid Yu Yang K_CONST,
85ebbfee1eSDavid Yu Yang K_ENUM,
86ebbfee1eSDavid Yu Yang K_ENUMERATOR,
87ebbfee1eSDavid Yu Yang K_PARAMETER,
88ebbfee1eSDavid Yu Yang K_LOCAL_VARIABLE,
89ebbfee1eSDavid Yu Yang K_SIGNAL,
90ebbfee1eSDavid Yu Yang COUNT_KIND
91ebbfee1eSDavid Yu Yang } gdscriptKind;
92ebbfee1eSDavid Yu Yang
93ebbfee1eSDavid Yu Yang typedef enum {
94ebbfee1eSDavid Yu Yang GDSCRIPT_CLASS_EXTENDED,
95ebbfee1eSDavid Yu Yang } gdscriptClassRole;
96ebbfee1eSDavid Yu Yang
97ebbfee1eSDavid Yu Yang static roleDefinition GDScriptClassRoles [] = {
98ebbfee1eSDavid Yu Yang { true, "extended", "used as a base class for extending" },
99ebbfee1eSDavid Yu Yang };
100ebbfee1eSDavid Yu Yang
101ebbfee1eSDavid Yu Yang static kindDefinition GDScriptKinds[COUNT_KIND] = {
102ebbfee1eSDavid Yu Yang {true, 'c', "class", "classes",
103ebbfee1eSDavid Yu Yang .referenceOnly = false, ATTACH_ROLES(GDScriptClassRoles)},
104ebbfee1eSDavid Yu Yang {true, 'm', "method", "methods"},
105ebbfee1eSDavid Yu Yang {true, 'v', "variable", "variables"},
106ebbfee1eSDavid Yu Yang {true, 'C', "const", "constants"},
107ebbfee1eSDavid Yu Yang {true, 'g', "enum", "enumeration names"},
108ebbfee1eSDavid Yu Yang {true, 'e', "enumerator", "enumerated values"},
109ebbfee1eSDavid Yu Yang {false,'z', "parameter", "function parameters"},
110ebbfee1eSDavid Yu Yang {false,'l', "local", "local variables"},
111ebbfee1eSDavid Yu Yang {true, 's', "signal", "signals"},
112ebbfee1eSDavid Yu Yang };
113ebbfee1eSDavid Yu Yang
114ebbfee1eSDavid Yu Yang typedef enum {
115ebbfee1eSDavid Yu Yang X_IMPLICIT_CLASS,
116ebbfee1eSDavid Yu Yang } gdscriptXtag;
117ebbfee1eSDavid Yu Yang
118ebbfee1eSDavid Yu Yang static xtagDefinition GDScriptXtagTable [] = {
119ebbfee1eSDavid Yu Yang {
120ebbfee1eSDavid Yu Yang .enabled = false,
121ebbfee1eSDavid Yu Yang .name = "implicitClass",
122ebbfee1eSDavid Yu Yang .description = "Include tag for the implicitly defined unnamed class",
123ebbfee1eSDavid Yu Yang },
124ebbfee1eSDavid Yu Yang };
125ebbfee1eSDavid Yu Yang
126ebbfee1eSDavid Yu Yang static const keywordTable GDScriptKeywordTable[] = {
127ebbfee1eSDavid Yu Yang /* keyword keyword ID */
128ebbfee1eSDavid Yu Yang { "class", KEYWORD_class },
129ebbfee1eSDavid Yu Yang { "func", KEYWORD_func },
130ebbfee1eSDavid Yu Yang { "extends", KEYWORD_extends },
131ebbfee1eSDavid Yu Yang { "lambda", KEYWORD_lambda }, // Future GDScript lambda currently uses func, may change
132ebbfee1eSDavid Yu Yang { "pass", KEYWORD_pass },
133ebbfee1eSDavid Yu Yang { "return", KEYWORD_return },
134ebbfee1eSDavid Yu Yang { "var", KEYWORD_variable },
135ebbfee1eSDavid Yu Yang { "const", KEYWORD_const },
136ebbfee1eSDavid Yu Yang { "enum", KEYWORD_enum },
137ebbfee1eSDavid Yu Yang { "class_name", KEYWORD_class_name },
138ebbfee1eSDavid Yu Yang { "signal", KEYWORD_signal },
139ebbfee1eSDavid Yu Yang
140ebbfee1eSDavid Yu Yang };
141ebbfee1eSDavid Yu Yang
142ebbfee1eSDavid Yu Yang const static struct keywordGroup modifierKeywords = {
143ebbfee1eSDavid Yu Yang .value = KEYWORD_modifier,
144ebbfee1eSDavid Yu Yang .addingUnlessExisting = false,
145ebbfee1eSDavid Yu Yang .keywords = {
146ebbfee1eSDavid Yu Yang "static",
147ebbfee1eSDavid Yu Yang "remote", "remotesync",
148ebbfee1eSDavid Yu Yang "master", "mastersycn",
149ebbfee1eSDavid Yu Yang "puppet", "puppetsync",
150ebbfee1eSDavid Yu Yang NULL,
151ebbfee1eSDavid Yu Yang },
152ebbfee1eSDavid Yu Yang };
153ebbfee1eSDavid Yu Yang
154ebbfee1eSDavid Yu Yang typedef enum eTokenType {
155ebbfee1eSDavid Yu Yang /* 0..255 are the byte's value */
156ebbfee1eSDavid Yu Yang TOKEN_EOF = 256,
157ebbfee1eSDavid Yu Yang TOKEN_UNDEFINED,
158ebbfee1eSDavid Yu Yang TOKEN_INDENT,
159ebbfee1eSDavid Yu Yang TOKEN_KEYWORD,
160ebbfee1eSDavid Yu Yang TOKEN_OPERATOR,
161ebbfee1eSDavid Yu Yang TOKEN_IDENTIFIER,
162ebbfee1eSDavid Yu Yang TOKEN_STRING,
163ebbfee1eSDavid Yu Yang TOKEN_ARROW, /* -> */
164ebbfee1eSDavid Yu Yang TOKEN_WHITESPACE,
165ebbfee1eSDavid Yu Yang } tokenType;
166ebbfee1eSDavid Yu Yang
167ebbfee1eSDavid Yu Yang typedef struct {
168ebbfee1eSDavid Yu Yang int type;
169ebbfee1eSDavid Yu Yang keywordId keyword;
170ebbfee1eSDavid Yu Yang vString * string;
171ebbfee1eSDavid Yu Yang int indent;
172ebbfee1eSDavid Yu Yang unsigned long lineNumber;
173ebbfee1eSDavid Yu Yang MIOPos filePosition;
174ebbfee1eSDavid Yu Yang } tokenInfo;
175ebbfee1eSDavid Yu Yang
176ebbfee1eSDavid Yu Yang struct gdscriptNestingLevelUserData {
177ebbfee1eSDavid Yu Yang int indentation;
178ebbfee1eSDavid Yu Yang };
179ebbfee1eSDavid Yu Yang #define GDS_NL(nl) ((struct gdscriptNestingLevelUserData *) nestingLevelGetUserData (nl))
180ebbfee1eSDavid Yu Yang
181ebbfee1eSDavid Yu Yang static langType Lang_gdscript;
182ebbfee1eSDavid Yu Yang static unsigned int TokenContinuationDepth = 0;
183ebbfee1eSDavid Yu Yang static tokenInfo *NextToken = NULL;
184ebbfee1eSDavid Yu Yang static NestingLevels *GDScriptNestingLevels = NULL;
185ebbfee1eSDavid Yu Yang static objPool *TokenPool = NULL;
186ebbfee1eSDavid Yu Yang
187ebbfee1eSDavid Yu Yang
188ebbfee1eSDavid Yu Yang // Always reports single-underscores as protected
accessFromIdentifier(const vString * const ident,int parentKind)189ebbfee1eSDavid Yu Yang static accessType accessFromIdentifier (const vString *const ident, int parentKind)
190ebbfee1eSDavid Yu Yang {
191ebbfee1eSDavid Yu Yang const char *const p = vStringValue (ident);
192ebbfee1eSDavid Yu Yang const size_t len = vStringLength (ident);
193ebbfee1eSDavid Yu Yang
194ebbfee1eSDavid Yu Yang /* inside a function/method, private */
195ebbfee1eSDavid Yu Yang if (parentKind != -1 && parentKind != K_CLASS)
196ebbfee1eSDavid Yu Yang return ACCESS_PRIVATE;
197ebbfee1eSDavid Yu Yang /* not starting with "_", public */
198ebbfee1eSDavid Yu Yang else if (len < 1 || p[0] != '_')
199ebbfee1eSDavid Yu Yang return ACCESS_PUBLIC;
200ebbfee1eSDavid Yu Yang /* "_...": suggested as non-public, but easily accessible */
201ebbfee1eSDavid Yu Yang else
202ebbfee1eSDavid Yu Yang return ACCESS_PROTECTED;
203ebbfee1eSDavid Yu Yang }
204ebbfee1eSDavid Yu Yang
initGDScriptEntry(tagEntryInfo * const e,const tokenInfo * const token,const gdscriptKind kind)205ebbfee1eSDavid Yu Yang static void initGDScriptEntry (tagEntryInfo *const e, const tokenInfo *const token,
206ebbfee1eSDavid Yu Yang const gdscriptKind kind)
207ebbfee1eSDavid Yu Yang {
208ebbfee1eSDavid Yu Yang accessType access;
209ebbfee1eSDavid Yu Yang int parentKind = -1;
210ebbfee1eSDavid Yu Yang NestingLevel *nl;
211ebbfee1eSDavid Yu Yang
212ebbfee1eSDavid Yu Yang initTagEntry (e, vStringValue (token->string), kind);
213ebbfee1eSDavid Yu Yang
214ebbfee1eSDavid Yu Yang e->lineNumber = token->lineNumber;
215ebbfee1eSDavid Yu Yang e->filePosition = token->filePosition;
216ebbfee1eSDavid Yu Yang
217ebbfee1eSDavid Yu Yang nl = nestingLevelsGetCurrent (GDScriptNestingLevels);
218ebbfee1eSDavid Yu Yang if (nl)
219ebbfee1eSDavid Yu Yang {
220ebbfee1eSDavid Yu Yang tagEntryInfo *nlEntry = getEntryOfNestingLevel (nl);
221ebbfee1eSDavid Yu Yang
222ebbfee1eSDavid Yu Yang e->extensionFields.scopeIndex = nl->corkIndex;
223ebbfee1eSDavid Yu Yang
224ebbfee1eSDavid Yu Yang /* nlEntry can be NULL if a kind was disabled. But what can we do
225ebbfee1eSDavid Yu Yang * here? Even disabled kinds should count for the hierarchy I
226ebbfee1eSDavid Yu Yang * guess -- as it'd otherwise be wrong -- but with cork we're
227ebbfee1eSDavid Yu Yang * fucked up as there's nothing to look up. Damn. */
228ebbfee1eSDavid Yu Yang if (nlEntry)
229ebbfee1eSDavid Yu Yang parentKind = nlEntry->kindIndex;
230ebbfee1eSDavid Yu Yang }
231ebbfee1eSDavid Yu Yang
232ebbfee1eSDavid Yu Yang access = accessFromIdentifier (token->string, parentKind);
233ebbfee1eSDavid Yu Yang e->extensionFields.access = GDScriptAccesses[access];
234ebbfee1eSDavid Yu Yang /* FIXME: should we really set isFileScope in addition to access? */
235ebbfee1eSDavid Yu Yang if (access == ACCESS_PRIVATE)
236ebbfee1eSDavid Yu Yang e->isFileScope = true;
237ebbfee1eSDavid Yu Yang }
238ebbfee1eSDavid Yu Yang
makeClassTag(const tokenInfo * const token,const vString * const inheritance)239ebbfee1eSDavid Yu Yang static int makeClassTag (const tokenInfo *const token,
240ebbfee1eSDavid Yu Yang const vString *const inheritance)
241ebbfee1eSDavid Yu Yang {
242ebbfee1eSDavid Yu Yang if (GDScriptKinds[K_CLASS].enabled)
243ebbfee1eSDavid Yu Yang {
244ebbfee1eSDavid Yu Yang tagEntryInfo e;
245ebbfee1eSDavid Yu Yang
246ebbfee1eSDavid Yu Yang initGDScriptEntry (&e, token, K_CLASS);
247ebbfee1eSDavid Yu Yang
248ebbfee1eSDavid Yu Yang e.extensionFields.inheritance = inheritance ? vStringValue (inheritance) : "";
249ebbfee1eSDavid Yu Yang
250ebbfee1eSDavid Yu Yang return makeTagEntry (&e);
251ebbfee1eSDavid Yu Yang }
252ebbfee1eSDavid Yu Yang
253ebbfee1eSDavid Yu Yang return CORK_NIL;
254ebbfee1eSDavid Yu Yang }
255ebbfee1eSDavid Yu Yang
makeDecoratorString(const stringList * const strlist)256ebbfee1eSDavid Yu Yang static vString *makeDecoratorString (const stringList *const strlist)
257ebbfee1eSDavid Yu Yang {
258ebbfee1eSDavid Yu Yang vString *vstr = vStringNew ();
259ebbfee1eSDavid Yu Yang
260ebbfee1eSDavid Yu Yang for (unsigned int i = 0; i < stringListCount (strlist); i++)
261ebbfee1eSDavid Yu Yang {
262ebbfee1eSDavid Yu Yang vString *elt = stringListItem (strlist, i);
263ebbfee1eSDavid Yu Yang if (i != 0 && (vStringValue (elt) > 0
264ebbfee1eSDavid Yu Yang && vStringValue (elt)[0] != '('))
265ebbfee1eSDavid Yu Yang vStringPut (vstr, ',');
266ebbfee1eSDavid Yu Yang vStringCat (vstr, elt);
267ebbfee1eSDavid Yu Yang }
268ebbfee1eSDavid Yu Yang return vstr;
269ebbfee1eSDavid Yu Yang }
270ebbfee1eSDavid Yu Yang
makeFunctionTag(const tokenInfo * const token,int kind,const vString * const arglist,const stringList * const decorators)271ebbfee1eSDavid Yu Yang static int makeFunctionTag (const tokenInfo *const token,
272ebbfee1eSDavid Yu Yang int kind,
273ebbfee1eSDavid Yu Yang const vString *const arglist,
274ebbfee1eSDavid Yu Yang const stringList *const decorators)
275ebbfee1eSDavid Yu Yang {
276ebbfee1eSDavid Yu Yang if (GDScriptKinds[kind].enabled)
277ebbfee1eSDavid Yu Yang {
278ebbfee1eSDavid Yu Yang tagEntryInfo e;
279ebbfee1eSDavid Yu Yang vString *vstr = NULL;
280ebbfee1eSDavid Yu Yang int r;
281ebbfee1eSDavid Yu Yang
282ebbfee1eSDavid Yu Yang initGDScriptEntry (&e, token, kind);
283ebbfee1eSDavid Yu Yang
284ebbfee1eSDavid Yu Yang if (arglist)
285ebbfee1eSDavid Yu Yang e.extensionFields.signature = vStringValue (arglist);
286ebbfee1eSDavid Yu Yang if (decorators && stringListCount (decorators) > 0)
287ebbfee1eSDavid Yu Yang {
288ebbfee1eSDavid Yu Yang vstr = makeDecoratorString (decorators);
289ebbfee1eSDavid Yu Yang attachParserField (&e, false, GDScriptFields[F_ANNOTATIONS].ftype,
290ebbfee1eSDavid Yu Yang vStringValue (vstr));
291ebbfee1eSDavid Yu Yang }
292ebbfee1eSDavid Yu Yang
293ebbfee1eSDavid Yu Yang r = makeTagEntry (&e);
294ebbfee1eSDavid Yu Yang vStringDelete (vstr); /* NULL is ignored. */
295ebbfee1eSDavid Yu Yang
296ebbfee1eSDavid Yu Yang return r;
297ebbfee1eSDavid Yu Yang }
298ebbfee1eSDavid Yu Yang
299ebbfee1eSDavid Yu Yang return CORK_NIL;
300ebbfee1eSDavid Yu Yang }
301ebbfee1eSDavid Yu Yang
makeSimpleGDScriptTag(const tokenInfo * const token,gdscriptKind const kind)302ebbfee1eSDavid Yu Yang static int makeSimpleGDScriptTag (const tokenInfo *const token, gdscriptKind const kind)
303ebbfee1eSDavid Yu Yang {
304ebbfee1eSDavid Yu Yang if (GDScriptKinds[kind].enabled)
305ebbfee1eSDavid Yu Yang {
306ebbfee1eSDavid Yu Yang tagEntryInfo e;
307ebbfee1eSDavid Yu Yang
308ebbfee1eSDavid Yu Yang initGDScriptEntry (&e, token, kind);
309ebbfee1eSDavid Yu Yang return makeTagEntry (&e);
310ebbfee1eSDavid Yu Yang }
311ebbfee1eSDavid Yu Yang
312ebbfee1eSDavid Yu Yang return CORK_NIL;
313ebbfee1eSDavid Yu Yang }
314ebbfee1eSDavid Yu Yang
makeSimpleGDScriptRefTag(const tokenInfo * const token,gdscriptKind const kind,int roleIndex,xtagType xtag)315ebbfee1eSDavid Yu Yang static int makeSimpleGDScriptRefTag (const tokenInfo *const token,
316ebbfee1eSDavid Yu Yang gdscriptKind const kind,
317ebbfee1eSDavid Yu Yang int roleIndex, xtagType xtag)
318ebbfee1eSDavid Yu Yang {
319ebbfee1eSDavid Yu Yang if (isXtagEnabled (XTAG_REFERENCE_TAGS))
320ebbfee1eSDavid Yu Yang {
321ebbfee1eSDavid Yu Yang tagEntryInfo e;
322ebbfee1eSDavid Yu Yang
323ebbfee1eSDavid Yu Yang initRefTagEntry (&e, vStringValue (token->string),
324ebbfee1eSDavid Yu Yang kind, roleIndex);
325ebbfee1eSDavid Yu Yang
326ebbfee1eSDavid Yu Yang e.lineNumber = token->lineNumber;
327ebbfee1eSDavid Yu Yang e.filePosition = token->filePosition;
328ebbfee1eSDavid Yu Yang
329ebbfee1eSDavid Yu Yang if (xtag != XTAG_UNKNOWN)
330ebbfee1eSDavid Yu Yang markTagExtraBit (&e, xtag);
331ebbfee1eSDavid Yu Yang
332ebbfee1eSDavid Yu Yang return makeTagEntry (&e);
333ebbfee1eSDavid Yu Yang }
334ebbfee1eSDavid Yu Yang
335ebbfee1eSDavid Yu Yang return CORK_NIL;
336ebbfee1eSDavid Yu Yang }
337ebbfee1eSDavid Yu Yang
newPoolToken(void * createArg CTAGS_ATTR_UNUSED)338ebbfee1eSDavid Yu Yang static void *newPoolToken (void *createArg CTAGS_ATTR_UNUSED)
339ebbfee1eSDavid Yu Yang {
340ebbfee1eSDavid Yu Yang tokenInfo *token = xMalloc (1, tokenInfo);
341ebbfee1eSDavid Yu Yang token->string = vStringNew ();
342ebbfee1eSDavid Yu Yang return token;
343ebbfee1eSDavid Yu Yang }
344ebbfee1eSDavid Yu Yang
deletePoolToken(void * data)345ebbfee1eSDavid Yu Yang static void deletePoolToken (void *data)
346ebbfee1eSDavid Yu Yang {
347ebbfee1eSDavid Yu Yang tokenInfo *token = data;
348ebbfee1eSDavid Yu Yang vStringDelete (token->string);
349ebbfee1eSDavid Yu Yang eFree (token);
350ebbfee1eSDavid Yu Yang }
351ebbfee1eSDavid Yu Yang
clearPoolToken(void * data)352ebbfee1eSDavid Yu Yang static void clearPoolToken (void *data)
353ebbfee1eSDavid Yu Yang {
354ebbfee1eSDavid Yu Yang tokenInfo *token = data;
355ebbfee1eSDavid Yu Yang
356ebbfee1eSDavid Yu Yang token->type = TOKEN_UNDEFINED;
357ebbfee1eSDavid Yu Yang token->keyword = KEYWORD_NONE;
358ebbfee1eSDavid Yu Yang token->indent = 0;
359ebbfee1eSDavid Yu Yang token->lineNumber = getInputLineNumber ();
360ebbfee1eSDavid Yu Yang token->filePosition = getInputFilePosition ();
361ebbfee1eSDavid Yu Yang vStringClear (token->string);
362ebbfee1eSDavid Yu Yang }
363ebbfee1eSDavid Yu Yang
copyToken(tokenInfo * const dest,const tokenInfo * const src)364ebbfee1eSDavid Yu Yang static void copyToken (tokenInfo *const dest, const tokenInfo *const src)
365ebbfee1eSDavid Yu Yang {
366ebbfee1eSDavid Yu Yang dest->lineNumber = src->lineNumber;
367ebbfee1eSDavid Yu Yang dest->filePosition = src->filePosition;
368ebbfee1eSDavid Yu Yang dest->type = src->type;
369ebbfee1eSDavid Yu Yang dest->keyword = src->keyword;
370ebbfee1eSDavid Yu Yang dest->indent = src->indent;
371ebbfee1eSDavid Yu Yang vStringCopy(dest->string, src->string);
372ebbfee1eSDavid Yu Yang }
373ebbfee1eSDavid Yu Yang
374ebbfee1eSDavid Yu Yang /* Skip a single or double quoted string. */
readString(vString * const string,const int delimiter)375ebbfee1eSDavid Yu Yang static void readString (vString *const string, const int delimiter)
376ebbfee1eSDavid Yu Yang {
377ebbfee1eSDavid Yu Yang int escaped = 0;
378ebbfee1eSDavid Yu Yang int c;
379ebbfee1eSDavid Yu Yang
380ebbfee1eSDavid Yu Yang while ((c = getcFromInputFile ()) != EOF)
381ebbfee1eSDavid Yu Yang {
382ebbfee1eSDavid Yu Yang if (escaped)
383ebbfee1eSDavid Yu Yang {
384ebbfee1eSDavid Yu Yang vStringPut (string, c);
385ebbfee1eSDavid Yu Yang escaped--;
386ebbfee1eSDavid Yu Yang }
387ebbfee1eSDavid Yu Yang else if (c == '\\')
388ebbfee1eSDavid Yu Yang escaped++;
389ebbfee1eSDavid Yu Yang else if (c == delimiter || c == '\n' || c == '\r')
390ebbfee1eSDavid Yu Yang {
391ebbfee1eSDavid Yu Yang if (c != delimiter)
392ebbfee1eSDavid Yu Yang ungetcToInputFile (c);
393ebbfee1eSDavid Yu Yang break;
394ebbfee1eSDavid Yu Yang }
395ebbfee1eSDavid Yu Yang else
396ebbfee1eSDavid Yu Yang vStringPut (string, c);
397ebbfee1eSDavid Yu Yang }
398ebbfee1eSDavid Yu Yang }
399ebbfee1eSDavid Yu Yang
400ebbfee1eSDavid Yu Yang /* Skip a single or double triple quoted string. */
readTripleString(vString * const string,const int delimiter)401ebbfee1eSDavid Yu Yang static void readTripleString (vString *const string, const int delimiter)
402ebbfee1eSDavid Yu Yang {
403ebbfee1eSDavid Yu Yang int c;
404ebbfee1eSDavid Yu Yang int escaped = 0;
405ebbfee1eSDavid Yu Yang int n = 0;
406ebbfee1eSDavid Yu Yang while ((c = getcFromInputFile ()) != EOF)
407ebbfee1eSDavid Yu Yang {
408ebbfee1eSDavid Yu Yang if (c == delimiter && ! escaped)
409ebbfee1eSDavid Yu Yang {
410ebbfee1eSDavid Yu Yang if (++n >= 3)
411ebbfee1eSDavid Yu Yang break;
412ebbfee1eSDavid Yu Yang }
413ebbfee1eSDavid Yu Yang else
414ebbfee1eSDavid Yu Yang {
415ebbfee1eSDavid Yu Yang for (; n > 0; n--)
416ebbfee1eSDavid Yu Yang vStringPut (string, delimiter);
417ebbfee1eSDavid Yu Yang if (c != '\\' || escaped)
418ebbfee1eSDavid Yu Yang vStringPut (string, c);
419ebbfee1eSDavid Yu Yang n = 0;
420ebbfee1eSDavid Yu Yang }
421ebbfee1eSDavid Yu Yang
422ebbfee1eSDavid Yu Yang if (escaped)
423ebbfee1eSDavid Yu Yang escaped--;
424ebbfee1eSDavid Yu Yang else if (c == '\\')
425ebbfee1eSDavid Yu Yang escaped++;
426ebbfee1eSDavid Yu Yang }
427ebbfee1eSDavid Yu Yang }
428ebbfee1eSDavid Yu Yang
readIdentifier(vString * const string,const int firstChar)429ebbfee1eSDavid Yu Yang static void readIdentifier (vString *const string, const int firstChar)
430ebbfee1eSDavid Yu Yang {
431ebbfee1eSDavid Yu Yang int c = firstChar;
432ebbfee1eSDavid Yu Yang do
433ebbfee1eSDavid Yu Yang {
434ebbfee1eSDavid Yu Yang vStringPut (string, c);
435ebbfee1eSDavid Yu Yang c = getcFromInputFile ();
436ebbfee1eSDavid Yu Yang }
437ebbfee1eSDavid Yu Yang while (isIdentifierChar (c));
438ebbfee1eSDavid Yu Yang ungetcToInputFile (c);
439ebbfee1eSDavid Yu Yang }
440ebbfee1eSDavid Yu Yang
ungetToken(tokenInfo * const token)441ebbfee1eSDavid Yu Yang static void ungetToken (tokenInfo *const token)
442ebbfee1eSDavid Yu Yang {
443ebbfee1eSDavid Yu Yang Assert (NextToken == NULL);
444ebbfee1eSDavid Yu Yang NextToken = newToken ();
445ebbfee1eSDavid Yu Yang copyToken (NextToken, token);
446ebbfee1eSDavid Yu Yang }
447ebbfee1eSDavid Yu Yang
readTokenFull(tokenInfo * const token,bool inclWhitespaces)448ebbfee1eSDavid Yu Yang static void readTokenFull (tokenInfo *const token, bool inclWhitespaces)
449ebbfee1eSDavid Yu Yang {
450ebbfee1eSDavid Yu Yang int c;
451ebbfee1eSDavid Yu Yang int n;
452ebbfee1eSDavid Yu Yang
453ebbfee1eSDavid Yu Yang /* if we've got a token held back, emit it */
454ebbfee1eSDavid Yu Yang if (NextToken)
455ebbfee1eSDavid Yu Yang {
456ebbfee1eSDavid Yu Yang copyToken (token, NextToken);
457ebbfee1eSDavid Yu Yang deleteToken (NextToken);
458ebbfee1eSDavid Yu Yang NextToken = NULL;
459ebbfee1eSDavid Yu Yang return;
460ebbfee1eSDavid Yu Yang }
461ebbfee1eSDavid Yu Yang
462ebbfee1eSDavid Yu Yang token->type = TOKEN_UNDEFINED;
463ebbfee1eSDavid Yu Yang token->keyword = KEYWORD_NONE;
464ebbfee1eSDavid Yu Yang vStringClear (token->string);
465ebbfee1eSDavid Yu Yang
466ebbfee1eSDavid Yu Yang getNextChar:
467ebbfee1eSDavid Yu Yang
468ebbfee1eSDavid Yu Yang n = 0;
469ebbfee1eSDavid Yu Yang do
470ebbfee1eSDavid Yu Yang {
471ebbfee1eSDavid Yu Yang c = getcFromInputFile ();
472ebbfee1eSDavid Yu Yang n++;
473ebbfee1eSDavid Yu Yang }
474ebbfee1eSDavid Yu Yang while (c == ' ' || c == '\t' || c == '\f');
475ebbfee1eSDavid Yu Yang
476ebbfee1eSDavid Yu Yang token->lineNumber = getInputLineNumber ();
477ebbfee1eSDavid Yu Yang token->filePosition = getInputFilePosition ();
478ebbfee1eSDavid Yu Yang
479ebbfee1eSDavid Yu Yang if (inclWhitespaces && n > 1 && c != '\r' && c != '\n')
480ebbfee1eSDavid Yu Yang {
481ebbfee1eSDavid Yu Yang ungetcToInputFile (c);
482ebbfee1eSDavid Yu Yang vStringPut (token->string, ' ');
483ebbfee1eSDavid Yu Yang token->type = TOKEN_WHITESPACE;
484ebbfee1eSDavid Yu Yang return;
485ebbfee1eSDavid Yu Yang }
486ebbfee1eSDavid Yu Yang
487ebbfee1eSDavid Yu Yang switch (c)
488ebbfee1eSDavid Yu Yang {
489ebbfee1eSDavid Yu Yang case EOF:
490ebbfee1eSDavid Yu Yang token->type = TOKEN_EOF;
491ebbfee1eSDavid Yu Yang break;
492ebbfee1eSDavid Yu Yang
493ebbfee1eSDavid Yu Yang case '\'':
494ebbfee1eSDavid Yu Yang case '"':
495ebbfee1eSDavid Yu Yang {
496ebbfee1eSDavid Yu Yang int d = getcFromInputFile ();
497ebbfee1eSDavid Yu Yang token->type = TOKEN_STRING;
498ebbfee1eSDavid Yu Yang vStringPut (token->string, c);
499ebbfee1eSDavid Yu Yang if (d != c)
500ebbfee1eSDavid Yu Yang {
501ebbfee1eSDavid Yu Yang ungetcToInputFile (d);
502ebbfee1eSDavid Yu Yang readString (token->string, c);
503ebbfee1eSDavid Yu Yang }
504ebbfee1eSDavid Yu Yang else if ((d = getcFromInputFile ()) == c)
505ebbfee1eSDavid Yu Yang readTripleString (token->string, c);
506ebbfee1eSDavid Yu Yang else /* empty string */
507ebbfee1eSDavid Yu Yang ungetcToInputFile (d);
508ebbfee1eSDavid Yu Yang vStringPut (token->string, c);
509ebbfee1eSDavid Yu Yang token->lineNumber = getInputLineNumber ();
510ebbfee1eSDavid Yu Yang token->filePosition = getInputFilePosition ();
511ebbfee1eSDavid Yu Yang break;
512ebbfee1eSDavid Yu Yang }
513ebbfee1eSDavid Yu Yang
514ebbfee1eSDavid Yu Yang case '=':
515ebbfee1eSDavid Yu Yang {
516ebbfee1eSDavid Yu Yang int d = getcFromInputFile ();
517ebbfee1eSDavid Yu Yang vStringPut (token->string, c);
518ebbfee1eSDavid Yu Yang if (d == c)
519ebbfee1eSDavid Yu Yang {
520ebbfee1eSDavid Yu Yang vStringPut (token->string, d);
521ebbfee1eSDavid Yu Yang token->type = TOKEN_OPERATOR;
522ebbfee1eSDavid Yu Yang }
523ebbfee1eSDavid Yu Yang else
524ebbfee1eSDavid Yu Yang {
525ebbfee1eSDavid Yu Yang ungetcToInputFile (d);
526ebbfee1eSDavid Yu Yang token->type = c;
527ebbfee1eSDavid Yu Yang }
528ebbfee1eSDavid Yu Yang break;
529ebbfee1eSDavid Yu Yang }
530ebbfee1eSDavid Yu Yang
531ebbfee1eSDavid Yu Yang case '-':
532ebbfee1eSDavid Yu Yang {
533ebbfee1eSDavid Yu Yang int d = getcFromInputFile ();
534ebbfee1eSDavid Yu Yang if (d == '>')
535ebbfee1eSDavid Yu Yang {
536ebbfee1eSDavid Yu Yang vStringPut (token->string, c);
537ebbfee1eSDavid Yu Yang vStringPut (token->string, d);
538ebbfee1eSDavid Yu Yang token->type = TOKEN_ARROW;
539ebbfee1eSDavid Yu Yang break;
540ebbfee1eSDavid Yu Yang }
541ebbfee1eSDavid Yu Yang ungetcToInputFile (d);
542ebbfee1eSDavid Yu Yang /* fall through */
543ebbfee1eSDavid Yu Yang }
544ebbfee1eSDavid Yu Yang case '+':
545ebbfee1eSDavid Yu Yang case '*':
546ebbfee1eSDavid Yu Yang case '%':
547ebbfee1eSDavid Yu Yang case '<':
548ebbfee1eSDavid Yu Yang case '>':
549ebbfee1eSDavid Yu Yang case '/':
550ebbfee1eSDavid Yu Yang {
551ebbfee1eSDavid Yu Yang int d = getcFromInputFile ();
552ebbfee1eSDavid Yu Yang vStringPut (token->string, c);
553ebbfee1eSDavid Yu Yang if (d != '=')
554ebbfee1eSDavid Yu Yang {
555ebbfee1eSDavid Yu Yang ungetcToInputFile (d);
556ebbfee1eSDavid Yu Yang token->type = c;
557ebbfee1eSDavid Yu Yang }
558ebbfee1eSDavid Yu Yang else
559ebbfee1eSDavid Yu Yang {
560ebbfee1eSDavid Yu Yang vStringPut (token->string, d);
561ebbfee1eSDavid Yu Yang token->type = TOKEN_OPERATOR;
562ebbfee1eSDavid Yu Yang }
563ebbfee1eSDavid Yu Yang break;
564ebbfee1eSDavid Yu Yang }
565ebbfee1eSDavid Yu Yang
566ebbfee1eSDavid Yu Yang /* eats newline to implement line continuation */
567ebbfee1eSDavid Yu Yang case '\\':
568ebbfee1eSDavid Yu Yang {
569ebbfee1eSDavid Yu Yang int d = getcFromInputFile ();
570ebbfee1eSDavid Yu Yang if (d == '\r')
571ebbfee1eSDavid Yu Yang d = getcFromInputFile ();
572ebbfee1eSDavid Yu Yang if (d != '\n')
573ebbfee1eSDavid Yu Yang ungetcToInputFile (d);
574ebbfee1eSDavid Yu Yang goto getNextChar;
575ebbfee1eSDavid Yu Yang }
576ebbfee1eSDavid Yu Yang
577ebbfee1eSDavid Yu Yang case '#': /* comment */
578ebbfee1eSDavid Yu Yang case '\r': /* newlines for indent */
579ebbfee1eSDavid Yu Yang case '\n':
580ebbfee1eSDavid Yu Yang {
581ebbfee1eSDavid Yu Yang int indent = 0;
582ebbfee1eSDavid Yu Yang do
583ebbfee1eSDavid Yu Yang {
584ebbfee1eSDavid Yu Yang if (c == '#')
585ebbfee1eSDavid Yu Yang {
586ebbfee1eSDavid Yu Yang do
587ebbfee1eSDavid Yu Yang c = getcFromInputFile ();
588ebbfee1eSDavid Yu Yang while (c != EOF && c != '\r' && c != '\n');
589ebbfee1eSDavid Yu Yang }
590ebbfee1eSDavid Yu Yang if (c == '\r')
591ebbfee1eSDavid Yu Yang {
592ebbfee1eSDavid Yu Yang int d = getcFromInputFile ();
593ebbfee1eSDavid Yu Yang if (d != '\n')
594ebbfee1eSDavid Yu Yang ungetcToInputFile (d);
595ebbfee1eSDavid Yu Yang }
596ebbfee1eSDavid Yu Yang indent = 0;
597ebbfee1eSDavid Yu Yang while ((c = getcFromInputFile ()) == ' ' || c == '\t' || c == '\f')
598ebbfee1eSDavid Yu Yang {
599ebbfee1eSDavid Yu Yang if (c == '\t')
600ebbfee1eSDavid Yu Yang indent += 8 - (indent % 8);
601ebbfee1eSDavid Yu Yang else if (c == '\f') /* yeah, it's weird */
602ebbfee1eSDavid Yu Yang indent = 0;
603ebbfee1eSDavid Yu Yang else
604ebbfee1eSDavid Yu Yang indent++;
605ebbfee1eSDavid Yu Yang }
606ebbfee1eSDavid Yu Yang } /* skip completely empty lines, so retry */
607ebbfee1eSDavid Yu Yang while (c == '\r' || c == '\n' || c == '#');
608ebbfee1eSDavid Yu Yang ungetcToInputFile (c);
609ebbfee1eSDavid Yu Yang if (TokenContinuationDepth > 0)
610ebbfee1eSDavid Yu Yang {
611ebbfee1eSDavid Yu Yang if (inclWhitespaces)
612ebbfee1eSDavid Yu Yang {
613ebbfee1eSDavid Yu Yang vStringPut (token->string, ' ');
614ebbfee1eSDavid Yu Yang token->type = TOKEN_WHITESPACE;
615ebbfee1eSDavid Yu Yang }
616ebbfee1eSDavid Yu Yang else
617ebbfee1eSDavid Yu Yang goto getNextChar;
618ebbfee1eSDavid Yu Yang }
619ebbfee1eSDavid Yu Yang else
620ebbfee1eSDavid Yu Yang {
621ebbfee1eSDavid Yu Yang token->type = TOKEN_INDENT;
622ebbfee1eSDavid Yu Yang token->indent = indent;
623ebbfee1eSDavid Yu Yang }
624ebbfee1eSDavid Yu Yang break;
625ebbfee1eSDavid Yu Yang }
626ebbfee1eSDavid Yu Yang
627ebbfee1eSDavid Yu Yang default:
628ebbfee1eSDavid Yu Yang if (! isIdentifierChar (c))
629ebbfee1eSDavid Yu Yang {
630ebbfee1eSDavid Yu Yang vStringPut (token->string, c);
631ebbfee1eSDavid Yu Yang token->type = c;
632ebbfee1eSDavid Yu Yang }
633ebbfee1eSDavid Yu Yang else
634ebbfee1eSDavid Yu Yang {
635ebbfee1eSDavid Yu Yang /* FIXME: handle U, B, R and F string prefixes? */
636ebbfee1eSDavid Yu Yang readIdentifier (token->string, c);
637ebbfee1eSDavid Yu Yang token->keyword = lookupKeyword (vStringValue (token->string), Lang_gdscript);
638ebbfee1eSDavid Yu Yang if (token->keyword == KEYWORD_NONE)
639ebbfee1eSDavid Yu Yang token->type = TOKEN_IDENTIFIER;
640ebbfee1eSDavid Yu Yang else
641ebbfee1eSDavid Yu Yang token->type = TOKEN_KEYWORD;
642ebbfee1eSDavid Yu Yang }
643ebbfee1eSDavid Yu Yang break;
644ebbfee1eSDavid Yu Yang }
645ebbfee1eSDavid Yu Yang
646ebbfee1eSDavid Yu Yang // handle implicit continuation lines not to emit INDENT inside brackets
647ebbfee1eSDavid Yu Yang if (token->type == '(' ||
648ebbfee1eSDavid Yu Yang token->type == '{' ||
649ebbfee1eSDavid Yu Yang token->type == '[')
650ebbfee1eSDavid Yu Yang {
651ebbfee1eSDavid Yu Yang TokenContinuationDepth ++;
652ebbfee1eSDavid Yu Yang }
653ebbfee1eSDavid Yu Yang else if (TokenContinuationDepth > 0 &&
654ebbfee1eSDavid Yu Yang (token->type == ')' ||
655ebbfee1eSDavid Yu Yang token->type == '}' ||
656ebbfee1eSDavid Yu Yang token->type == ']'))
657ebbfee1eSDavid Yu Yang {
658ebbfee1eSDavid Yu Yang TokenContinuationDepth --;
659ebbfee1eSDavid Yu Yang }
660ebbfee1eSDavid Yu Yang }
661ebbfee1eSDavid Yu Yang
readToken(tokenInfo * const token)662ebbfee1eSDavid Yu Yang static void readToken (tokenInfo *const token)
663ebbfee1eSDavid Yu Yang {
664ebbfee1eSDavid Yu Yang readTokenFull (token, false);
665ebbfee1eSDavid Yu Yang }
666ebbfee1eSDavid Yu Yang
667ebbfee1eSDavid Yu Yang /*================================= parsing =================================*/
668ebbfee1eSDavid Yu Yang
669ebbfee1eSDavid Yu Yang
reprCat(vString * const repr,const tokenInfo * const token)670ebbfee1eSDavid Yu Yang static void reprCat (vString *const repr, const tokenInfo *const token)
671ebbfee1eSDavid Yu Yang {
672ebbfee1eSDavid Yu Yang if (token->type != TOKEN_INDENT &&
673ebbfee1eSDavid Yu Yang token->type != TOKEN_WHITESPACE)
674ebbfee1eSDavid Yu Yang {
675ebbfee1eSDavid Yu Yang vStringCat (repr, token->string);
676ebbfee1eSDavid Yu Yang }
677ebbfee1eSDavid Yu Yang else if (vStringLength (repr) > 0 && vStringLast (repr) != ' ')
678ebbfee1eSDavid Yu Yang {
679ebbfee1eSDavid Yu Yang vStringPut (repr, ' ');
680ebbfee1eSDavid Yu Yang }
681ebbfee1eSDavid Yu Yang }
682ebbfee1eSDavid Yu Yang
skipOverPair(tokenInfo * const token,int tOpen,int tClose,vString * const repr,bool reprOuterPair)683ebbfee1eSDavid Yu Yang static bool skipOverPair (tokenInfo *const token, int tOpen, int tClose,
684ebbfee1eSDavid Yu Yang vString *const repr, bool reprOuterPair)
685ebbfee1eSDavid Yu Yang {
686ebbfee1eSDavid Yu Yang if (token->type == tOpen)
687ebbfee1eSDavid Yu Yang {
688ebbfee1eSDavid Yu Yang int depth = 1;
689ebbfee1eSDavid Yu Yang
690ebbfee1eSDavid Yu Yang if (repr && reprOuterPair)
691ebbfee1eSDavid Yu Yang reprCat (repr, token);
692ebbfee1eSDavid Yu Yang do
693ebbfee1eSDavid Yu Yang {
694ebbfee1eSDavid Yu Yang readTokenFull (token, true);
695ebbfee1eSDavid Yu Yang if (repr && (reprOuterPair || token->type != tClose || depth > 1))
696ebbfee1eSDavid Yu Yang {
697ebbfee1eSDavid Yu Yang reprCat (repr, token);
698ebbfee1eSDavid Yu Yang }
699ebbfee1eSDavid Yu Yang if (token->type == tOpen)
700ebbfee1eSDavid Yu Yang depth ++;
701ebbfee1eSDavid Yu Yang else if (token->type == tClose)
702ebbfee1eSDavid Yu Yang depth --;
703ebbfee1eSDavid Yu Yang }
704ebbfee1eSDavid Yu Yang while (token->type != TOKEN_EOF && depth > 0);
705ebbfee1eSDavid Yu Yang }
706ebbfee1eSDavid Yu Yang
707ebbfee1eSDavid Yu Yang return token->type == tClose;
708ebbfee1eSDavid Yu Yang }
709ebbfee1eSDavid Yu Yang
readQualifiedName(tokenInfo * const nameToken)710ebbfee1eSDavid Yu Yang static void readQualifiedName (tokenInfo *const nameToken)
711ebbfee1eSDavid Yu Yang {
712ebbfee1eSDavid Yu Yang readToken (nameToken);
713ebbfee1eSDavid Yu Yang
714ebbfee1eSDavid Yu Yang if (nameToken->type == TOKEN_IDENTIFIER ||
715ebbfee1eSDavid Yu Yang nameToken->type == '.')
716ebbfee1eSDavid Yu Yang {
717ebbfee1eSDavid Yu Yang vString *qualifiedName = vStringNew ();
718ebbfee1eSDavid Yu Yang tokenInfo *token = newToken ();
719ebbfee1eSDavid Yu Yang
720ebbfee1eSDavid Yu Yang while (nameToken->type == TOKEN_IDENTIFIER ||
721ebbfee1eSDavid Yu Yang nameToken->type == '.')
722ebbfee1eSDavid Yu Yang {
723ebbfee1eSDavid Yu Yang vStringCat (qualifiedName, nameToken->string);
724ebbfee1eSDavid Yu Yang copyToken (token, nameToken);
725ebbfee1eSDavid Yu Yang
726ebbfee1eSDavid Yu Yang readToken (nameToken);
727ebbfee1eSDavid Yu Yang }
728ebbfee1eSDavid Yu Yang /* put the last, non-matching, token back */
729ebbfee1eSDavid Yu Yang ungetToken (nameToken);
730ebbfee1eSDavid Yu Yang
731ebbfee1eSDavid Yu Yang copyToken (nameToken, token);
732ebbfee1eSDavid Yu Yang nameToken->type = TOKEN_IDENTIFIER;
733ebbfee1eSDavid Yu Yang vStringCopy (nameToken->string, qualifiedName);
734ebbfee1eSDavid Yu Yang
735ebbfee1eSDavid Yu Yang deleteToken (token);
736ebbfee1eSDavid Yu Yang vStringDelete (qualifiedName);
737ebbfee1eSDavid Yu Yang }
738ebbfee1eSDavid Yu Yang }
739ebbfee1eSDavid Yu Yang
parseParamTypeAnnotation(tokenInfo * const token,vString * arglist)740ebbfee1eSDavid Yu Yang static vString *parseParamTypeAnnotation (tokenInfo *const token,
741ebbfee1eSDavid Yu Yang vString *arglist)
742ebbfee1eSDavid Yu Yang {
743ebbfee1eSDavid Yu Yang readToken (token);
744ebbfee1eSDavid Yu Yang if (token->type != ':')
745ebbfee1eSDavid Yu Yang {
746ebbfee1eSDavid Yu Yang ungetToken (token);
747ebbfee1eSDavid Yu Yang return NULL;
748ebbfee1eSDavid Yu Yang }
749ebbfee1eSDavid Yu Yang
750ebbfee1eSDavid Yu Yang reprCat (arglist, token);
751ebbfee1eSDavid Yu Yang int depth = 0;
752ebbfee1eSDavid Yu Yang vString *t = vStringNew ();
753ebbfee1eSDavid Yu Yang while (true)
754ebbfee1eSDavid Yu Yang {
755ebbfee1eSDavid Yu Yang readTokenFull (token, true);
756ebbfee1eSDavid Yu Yang if (token->type == TOKEN_WHITESPACE)
757ebbfee1eSDavid Yu Yang {
758ebbfee1eSDavid Yu Yang reprCat (arglist, token);
759ebbfee1eSDavid Yu Yang continue;
760ebbfee1eSDavid Yu Yang }
761ebbfee1eSDavid Yu Yang else if (token->type == TOKEN_EOF)
762ebbfee1eSDavid Yu Yang break;
763ebbfee1eSDavid Yu Yang
764ebbfee1eSDavid Yu Yang if (token->type == '(' ||
765ebbfee1eSDavid Yu Yang token->type == '[' ||
766ebbfee1eSDavid Yu Yang token->type == '{')
767ebbfee1eSDavid Yu Yang depth ++;
768ebbfee1eSDavid Yu Yang else if (token->type == ')' ||
769ebbfee1eSDavid Yu Yang token->type == ']' ||
770ebbfee1eSDavid Yu Yang token->type == '}')
771ebbfee1eSDavid Yu Yang depth --;
772ebbfee1eSDavid Yu Yang
773ebbfee1eSDavid Yu Yang if (depth < 0
774ebbfee1eSDavid Yu Yang || (depth == 0 && (token->type == '='
775ebbfee1eSDavid Yu Yang || token->type == ',')))
776ebbfee1eSDavid Yu Yang {
777ebbfee1eSDavid Yu Yang ungetToken (token);
778ebbfee1eSDavid Yu Yang return t;
779ebbfee1eSDavid Yu Yang }
780ebbfee1eSDavid Yu Yang reprCat (arglist, token);
781ebbfee1eSDavid Yu Yang reprCat (t, token);
782ebbfee1eSDavid Yu Yang }
783ebbfee1eSDavid Yu Yang vStringDelete (t);
784ebbfee1eSDavid Yu Yang return NULL;
785ebbfee1eSDavid Yu Yang }
786ebbfee1eSDavid Yu Yang
parseReturnTypeAnnotation(tokenInfo * const token)787ebbfee1eSDavid Yu Yang static vString *parseReturnTypeAnnotation (tokenInfo *const token)
788ebbfee1eSDavid Yu Yang {
789ebbfee1eSDavid Yu Yang readToken (token);
790ebbfee1eSDavid Yu Yang if (token->type != TOKEN_ARROW)
791ebbfee1eSDavid Yu Yang {
792ebbfee1eSDavid Yu Yang return NULL;
793ebbfee1eSDavid Yu Yang }
794ebbfee1eSDavid Yu Yang
795ebbfee1eSDavid Yu Yang int depth = 0;
796ebbfee1eSDavid Yu Yang vString *t = vStringNew ();
797ebbfee1eSDavid Yu Yang while (true)
798ebbfee1eSDavid Yu Yang {
799ebbfee1eSDavid Yu Yang readToken (token);
800ebbfee1eSDavid Yu Yang if (token->type == TOKEN_EOF)
801ebbfee1eSDavid Yu Yang break;
802ebbfee1eSDavid Yu Yang
803ebbfee1eSDavid Yu Yang if (token->type == '(' ||
804ebbfee1eSDavid Yu Yang token->type == '[' ||
805ebbfee1eSDavid Yu Yang token->type == '{')
806ebbfee1eSDavid Yu Yang depth ++;
807ebbfee1eSDavid Yu Yang else if (token->type == ')' ||
808ebbfee1eSDavid Yu Yang token->type == ']' ||
809ebbfee1eSDavid Yu Yang token->type == '}')
810ebbfee1eSDavid Yu Yang depth --;
811ebbfee1eSDavid Yu Yang if (depth == 0 && token->type == ':')
812ebbfee1eSDavid Yu Yang {
813ebbfee1eSDavid Yu Yang ungetToken (token);
814ebbfee1eSDavid Yu Yang return t;
815ebbfee1eSDavid Yu Yang }
816ebbfee1eSDavid Yu Yang else
817ebbfee1eSDavid Yu Yang reprCat (t, token);
818ebbfee1eSDavid Yu Yang }
819ebbfee1eSDavid Yu Yang vStringDelete (t);
820ebbfee1eSDavid Yu Yang return NULL;
821ebbfee1eSDavid Yu Yang }
822ebbfee1eSDavid Yu Yang
parseClassOrDef(tokenInfo * const token,const stringList * const decorators,gdscriptKind kind)823ebbfee1eSDavid Yu Yang static bool parseClassOrDef (tokenInfo *const token,
824ebbfee1eSDavid Yu Yang const stringList *const decorators,
825*385c6b89SMasatake YAMATO gdscriptKind kind)
826ebbfee1eSDavid Yu Yang {
827ebbfee1eSDavid Yu Yang vString *arglist = NULL;
828ebbfee1eSDavid Yu Yang tokenInfo *name = NULL;
829ebbfee1eSDavid Yu Yang tokenInfo *parameterTokens[16] = { NULL };
830ebbfee1eSDavid Yu Yang vString *parameterTypes [ARRAY_SIZE(parameterTokens)] = { NULL };
831ebbfee1eSDavid Yu Yang unsigned int parameterCount = 0;
832ebbfee1eSDavid Yu Yang NestingLevel *lv;
833ebbfee1eSDavid Yu Yang int corkIndex;
834ebbfee1eSDavid Yu Yang
835ebbfee1eSDavid Yu Yang readToken (token);
836ebbfee1eSDavid Yu Yang if (token->type != TOKEN_IDENTIFIER)
837ebbfee1eSDavid Yu Yang return false;
838ebbfee1eSDavid Yu Yang
839ebbfee1eSDavid Yu Yang name = newToken ();
840ebbfee1eSDavid Yu Yang copyToken (name, token);
841ebbfee1eSDavid Yu Yang
842ebbfee1eSDavid Yu Yang readToken (token);
843ebbfee1eSDavid Yu Yang /* collect parameters or inheritance */
844ebbfee1eSDavid Yu Yang if (token->type == '(')
845ebbfee1eSDavid Yu Yang {
846ebbfee1eSDavid Yu Yang int prevTokenType = token->type;
847ebbfee1eSDavid Yu Yang int depth = 1;
848ebbfee1eSDavid Yu Yang
849ebbfee1eSDavid Yu Yang arglist = vStringNew ();
850ebbfee1eSDavid Yu Yang if (kind != K_CLASS)
851ebbfee1eSDavid Yu Yang reprCat (arglist, token);
852ebbfee1eSDavid Yu Yang
853ebbfee1eSDavid Yu Yang do
854ebbfee1eSDavid Yu Yang {
855ebbfee1eSDavid Yu Yang if (token->type != TOKEN_WHITESPACE &&
856ebbfee1eSDavid Yu Yang token->type != '*')
857ebbfee1eSDavid Yu Yang {
858ebbfee1eSDavid Yu Yang prevTokenType = token->type;
859ebbfee1eSDavid Yu Yang }
860ebbfee1eSDavid Yu Yang
861ebbfee1eSDavid Yu Yang readTokenFull (token, true);
862ebbfee1eSDavid Yu Yang if (kind != K_CLASS || token->type != ')' || depth > 1)
863ebbfee1eSDavid Yu Yang reprCat (arglist, token);
864ebbfee1eSDavid Yu Yang
865ebbfee1eSDavid Yu Yang if (token->type == '(' ||
866ebbfee1eSDavid Yu Yang token->type == '[' ||
867ebbfee1eSDavid Yu Yang token->type == '{')
868ebbfee1eSDavid Yu Yang depth ++;
869ebbfee1eSDavid Yu Yang else if (token->type == ')' ||
870ebbfee1eSDavid Yu Yang token->type == ']' ||
871ebbfee1eSDavid Yu Yang token->type == '}')
872ebbfee1eSDavid Yu Yang depth --;
873ebbfee1eSDavid Yu Yang else if (kind != K_CLASS && depth == 1 &&
874ebbfee1eSDavid Yu Yang token->type == TOKEN_IDENTIFIER &&
875ebbfee1eSDavid Yu Yang (prevTokenType == '(' || prevTokenType == ',') &&
876ebbfee1eSDavid Yu Yang parameterCount < ARRAY_SIZE (parameterTokens) &&
877ebbfee1eSDavid Yu Yang GDScriptKinds[K_PARAMETER].enabled)
878ebbfee1eSDavid Yu Yang {
879ebbfee1eSDavid Yu Yang tokenInfo *parameterName = newToken ();
880ebbfee1eSDavid Yu Yang
881ebbfee1eSDavid Yu Yang copyToken (parameterName, token);
882ebbfee1eSDavid Yu Yang parameterTokens[parameterCount] = parameterName;
883ebbfee1eSDavid Yu Yang parameterTypes [parameterCount++] = parseParamTypeAnnotation (token, arglist);
884ebbfee1eSDavid Yu Yang }
885ebbfee1eSDavid Yu Yang }
886ebbfee1eSDavid Yu Yang while (token->type != TOKEN_EOF && depth > 0);
887ebbfee1eSDavid Yu Yang }
888ebbfee1eSDavid Yu Yang else if (token->type == TOKEN_KEYWORD && token->keyword == KEYWORD_extends)
889ebbfee1eSDavid Yu Yang {
890ebbfee1eSDavid Yu Yang readToken (token);
891ebbfee1eSDavid Yu Yang if (token->type == TOKEN_IDENTIFIER)
892ebbfee1eSDavid Yu Yang {
893ebbfee1eSDavid Yu Yang makeSimpleGDScriptRefTag (token, K_CLASS, GDSCRIPT_CLASS_EXTENDED, XTAG_UNKNOWN);
894ebbfee1eSDavid Yu Yang arglist = vStringNewCopy (token->string);
895ebbfee1eSDavid Yu Yang }
896ebbfee1eSDavid Yu Yang }
897ebbfee1eSDavid Yu Yang else if (kind == K_SIGNAL)
898ebbfee1eSDavid Yu Yang {
899ebbfee1eSDavid Yu Yang /* signal can be defined with no parameter list. */
900ebbfee1eSDavid Yu Yang ungetToken (token);
901ebbfee1eSDavid Yu Yang }
902ebbfee1eSDavid Yu Yang
903ebbfee1eSDavid Yu Yang if (kind == K_CLASS)
904ebbfee1eSDavid Yu Yang corkIndex = makeClassTag (name, arglist);
905ebbfee1eSDavid Yu Yang else
906ebbfee1eSDavid Yu Yang corkIndex = makeFunctionTag (name, kind, arglist, decorators);
907ebbfee1eSDavid Yu Yang
908ebbfee1eSDavid Yu Yang lv = nestingLevelsPush (GDScriptNestingLevels, corkIndex);
909ebbfee1eSDavid Yu Yang GDS_NL (lv)->indentation = token->indent;
910ebbfee1eSDavid Yu Yang
911ebbfee1eSDavid Yu Yang deleteToken (name);
912ebbfee1eSDavid Yu Yang vStringDelete (arglist);
913ebbfee1eSDavid Yu Yang
914ebbfee1eSDavid Yu Yang if (parameterCount > 0)
915ebbfee1eSDavid Yu Yang {
916ebbfee1eSDavid Yu Yang unsigned int i;
917ebbfee1eSDavid Yu Yang
918ebbfee1eSDavid Yu Yang for (i = 0; i < parameterCount; i++)
919ebbfee1eSDavid Yu Yang {
920ebbfee1eSDavid Yu Yang int paramCorkIndex = makeSimpleGDScriptTag (parameterTokens[i], K_PARAMETER);
921ebbfee1eSDavid Yu Yang deleteToken (parameterTokens[i]);
922ebbfee1eSDavid Yu Yang tagEntryInfo *e = getEntryInCorkQueue (paramCorkIndex);
923ebbfee1eSDavid Yu Yang if (e && parameterTypes[i])
924ebbfee1eSDavid Yu Yang {
925ebbfee1eSDavid Yu Yang e->extensionFields.typeRef [0] = eStrdup ("typename");
926ebbfee1eSDavid Yu Yang e->extensionFields.typeRef [1] = vStringDeleteUnwrap (parameterTypes[i]);
927ebbfee1eSDavid Yu Yang parameterTypes[i] = NULL;
928ebbfee1eSDavid Yu Yang }
929ebbfee1eSDavid Yu Yang vStringDelete (parameterTypes[i]); /* NULL is acceptable. */
930ebbfee1eSDavid Yu Yang }
931ebbfee1eSDavid Yu Yang }
932ebbfee1eSDavid Yu Yang
933ebbfee1eSDavid Yu Yang tagEntryInfo *e;
934ebbfee1eSDavid Yu Yang vString *t;
935ebbfee1eSDavid Yu Yang if (kind != K_CLASS
936ebbfee1eSDavid Yu Yang && (e = getEntryInCorkQueue (corkIndex))
937ebbfee1eSDavid Yu Yang && (t = parseReturnTypeAnnotation (token)))
938ebbfee1eSDavid Yu Yang {
939ebbfee1eSDavid Yu Yang e->extensionFields.typeRef [0] = eStrdup ("typename");
940ebbfee1eSDavid Yu Yang e->extensionFields.typeRef [1] = vStringDeleteUnwrap (t);
941ebbfee1eSDavid Yu Yang }
942ebbfee1eSDavid Yu Yang
943ebbfee1eSDavid Yu Yang if (kind == K_SIGNAL)
944ebbfee1eSDavid Yu Yang nestingLevelsPop (GDScriptNestingLevels);
945ebbfee1eSDavid Yu Yang
946ebbfee1eSDavid Yu Yang return true;
947ebbfee1eSDavid Yu Yang }
948ebbfee1eSDavid Yu Yang
parseEnum(tokenInfo * const token)949ebbfee1eSDavid Yu Yang static bool parseEnum (tokenInfo *const token)
950ebbfee1eSDavid Yu Yang {
951ebbfee1eSDavid Yu Yang int corkIndex;
952ebbfee1eSDavid Yu Yang
953ebbfee1eSDavid Yu Yang readToken (token);
954ebbfee1eSDavid Yu Yang
955ebbfee1eSDavid Yu Yang if (token->type == '{')
956ebbfee1eSDavid Yu Yang {
957ebbfee1eSDavid Yu Yang tokenInfo *name = newToken ();
958ebbfee1eSDavid Yu Yang copyToken (name, token);
959ebbfee1eSDavid Yu Yang vStringClear (name->string);
960ebbfee1eSDavid Yu Yang anonGenerate (name->string, "anon_enum_", K_ENUM);
961ebbfee1eSDavid Yu Yang name->type = TOKEN_IDENTIFIER;
962ebbfee1eSDavid Yu Yang corkIndex = makeSimpleGDScriptTag (name, K_ENUM);
963ebbfee1eSDavid Yu Yang deleteToken (name);
964ebbfee1eSDavid Yu Yang tagEntryInfo *e = getEntryInCorkQueue (corkIndex);
965ebbfee1eSDavid Yu Yang if (e)
966ebbfee1eSDavid Yu Yang markTagExtraBit (e, XTAG_ANONYMOUS);
967ebbfee1eSDavid Yu Yang }
968ebbfee1eSDavid Yu Yang else if (token->type == TOKEN_IDENTIFIER)
969ebbfee1eSDavid Yu Yang {
970ebbfee1eSDavid Yu Yang corkIndex = makeSimpleGDScriptTag(token, K_ENUM);
971ebbfee1eSDavid Yu Yang readToken (token);
972ebbfee1eSDavid Yu Yang }
973ebbfee1eSDavid Yu Yang else
974ebbfee1eSDavid Yu Yang return false;
975ebbfee1eSDavid Yu Yang
976ebbfee1eSDavid Yu Yang if (token->type != '{')
977ebbfee1eSDavid Yu Yang return false;
978ebbfee1eSDavid Yu Yang
979ebbfee1eSDavid Yu Yang readToken (token);
980ebbfee1eSDavid Yu Yang nestingLevelsPush (GDScriptNestingLevels, corkIndex);
981ebbfee1eSDavid Yu Yang
982ebbfee1eSDavid Yu Yang while (token->type != '}' && token->type != TOKEN_EOF)
983ebbfee1eSDavid Yu Yang {
984ebbfee1eSDavid Yu Yang if (token->type == TOKEN_IDENTIFIER)
985ebbfee1eSDavid Yu Yang makeSimpleGDScriptTag(token, K_ENUMERATOR);
986ebbfee1eSDavid Yu Yang else if (token->type == '=')
987ebbfee1eSDavid Yu Yang {
988ebbfee1eSDavid Yu Yang /* Skip the right value. */
989ebbfee1eSDavid Yu Yang do
990ebbfee1eSDavid Yu Yang readToken (token);
991ebbfee1eSDavid Yu Yang while (token->type != ','
992ebbfee1eSDavid Yu Yang && token->type != '}'
993ebbfee1eSDavid Yu Yang && token->type != TOKEN_EOF);
994ebbfee1eSDavid Yu Yang if (token->type != ',')
995ebbfee1eSDavid Yu Yang continue;
996ebbfee1eSDavid Yu Yang }
997ebbfee1eSDavid Yu Yang readToken (token);
998ebbfee1eSDavid Yu Yang }
999ebbfee1eSDavid Yu Yang
1000ebbfee1eSDavid Yu Yang tagEntryInfo *e;
1001ebbfee1eSDavid Yu Yang vString *t;
1002ebbfee1eSDavid Yu Yang if ((e = getEntryInCorkQueue (corkIndex))
1003ebbfee1eSDavid Yu Yang && (t = parseReturnTypeAnnotation (token)))
1004ebbfee1eSDavid Yu Yang {
1005ebbfee1eSDavid Yu Yang e->extensionFields.typeRef [0] = eStrdup ("typename");
1006ebbfee1eSDavid Yu Yang e->extensionFields.typeRef [1] = vStringDeleteUnwrap (t);
1007ebbfee1eSDavid Yu Yang }
1008ebbfee1eSDavid Yu Yang
1009ebbfee1eSDavid Yu Yang nestingLevelsPop (GDScriptNestingLevels);
1010ebbfee1eSDavid Yu Yang return true;
1011ebbfee1eSDavid Yu Yang }
1012ebbfee1eSDavid Yu Yang
parseClassName(tokenInfo * const token)1013ebbfee1eSDavid Yu Yang static bool parseClassName (tokenInfo *const token)
1014ebbfee1eSDavid Yu Yang {
1015ebbfee1eSDavid Yu Yang readToken (token);
1016ebbfee1eSDavid Yu Yang if (token->type == TOKEN_IDENTIFIER)
1017ebbfee1eSDavid Yu Yang {
1018ebbfee1eSDavid Yu Yang /* A class name is explicitly given with "class_name" keyword.
1019ebbfee1eSDavid Yu Yang * Let's overwrite the anonymous tag for the class
1020ebbfee1eSDavid Yu Yang */
1021ebbfee1eSDavid Yu Yang NestingLevel *nl = nestingLevelsGetNthFromRoot (GDScriptNestingLevels, 0);
1022ebbfee1eSDavid Yu Yang tagEntryInfo *klass = nl? getEntryInCorkQueue (nl->corkIndex): NULL;
1023ebbfee1eSDavid Yu Yang
1024ebbfee1eSDavid Yu Yang tagEntryInfo e;
1025ebbfee1eSDavid Yu Yang char *name = vStringStrdup (token->string);
1026ebbfee1eSDavid Yu Yang initTagEntry (&e, klass? "UNUSED": name, K_CLASS);
1027ebbfee1eSDavid Yu Yang
1028ebbfee1eSDavid Yu Yang if (klass)
1029ebbfee1eSDavid Yu Yang {
1030ebbfee1eSDavid Yu Yang eFree ((void *)klass->name);
1031ebbfee1eSDavid Yu Yang klass->name = name;
1032ebbfee1eSDavid Yu Yang name = NULL;
1033ebbfee1eSDavid Yu Yang unmarkTagExtraBit(klass, XTAG_ANONYMOUS);
1034ebbfee1eSDavid Yu Yang
1035ebbfee1eSDavid Yu Yang /* Adjust the position. */
1036ebbfee1eSDavid Yu Yang setTagPositionFromTag (klass, &e);
1037ebbfee1eSDavid Yu Yang }
1038ebbfee1eSDavid Yu Yang
1039ebbfee1eSDavid Yu Yang /* Extract B in class_name C extends B */
1040ebbfee1eSDavid Yu Yang readToken (token);
1041ebbfee1eSDavid Yu Yang if (token->type == TOKEN_KEYWORD
1042ebbfee1eSDavid Yu Yang && token->keyword == KEYWORD_extends)
1043ebbfee1eSDavid Yu Yang {
1044ebbfee1eSDavid Yu Yang readToken (token);
1045ebbfee1eSDavid Yu Yang if (token->type == TOKEN_IDENTIFIER)
1046ebbfee1eSDavid Yu Yang {
1047ebbfee1eSDavid Yu Yang makeSimpleGDScriptRefTag (token, K_CLASS,
1048ebbfee1eSDavid Yu Yang GDSCRIPT_CLASS_EXTENDED,
1049ebbfee1eSDavid Yu Yang XTAG_UNKNOWN);
1050ebbfee1eSDavid Yu Yang if (klass)
1051ebbfee1eSDavid Yu Yang {
1052ebbfee1eSDavid Yu Yang if (klass->extensionFields.inheritance)
1053ebbfee1eSDavid Yu Yang eFree ((void *)klass->extensionFields.inheritance);
1054ebbfee1eSDavid Yu Yang klass->extensionFields.inheritance = vStringStrdup (token->string);
1055ebbfee1eSDavid Yu Yang }
1056ebbfee1eSDavid Yu Yang else
1057ebbfee1eSDavid Yu Yang e.extensionFields.inheritance = vStringValue(token->string);
1058ebbfee1eSDavid Yu Yang }
1059ebbfee1eSDavid Yu Yang }
1060ebbfee1eSDavid Yu Yang
1061ebbfee1eSDavid Yu Yang if (!klass)
1062ebbfee1eSDavid Yu Yang makeTagEntry (&e);
1063ebbfee1eSDavid Yu Yang
1064ebbfee1eSDavid Yu Yang if (name)
1065ebbfee1eSDavid Yu Yang eFree (name);
1066ebbfee1eSDavid Yu Yang }
1067ebbfee1eSDavid Yu Yang
1068ebbfee1eSDavid Yu Yang while (token->type != TOKEN_EOF &&
1069ebbfee1eSDavid Yu Yang token->type != ';' &&
1070ebbfee1eSDavid Yu Yang token->type != TOKEN_INDENT)
1071ebbfee1eSDavid Yu Yang readToken (token);
1072ebbfee1eSDavid Yu Yang
1073ebbfee1eSDavid Yu Yang return false;
1074ebbfee1eSDavid Yu Yang }
1075ebbfee1eSDavid Yu Yang
parseExtends(tokenInfo * const token)1076ebbfee1eSDavid Yu Yang static bool parseExtends (tokenInfo *const token)
1077ebbfee1eSDavid Yu Yang {
1078ebbfee1eSDavid Yu Yang if (token->keyword == KEYWORD_extends)
1079ebbfee1eSDavid Yu Yang {
1080ebbfee1eSDavid Yu Yang readQualifiedName (token);
1081ebbfee1eSDavid Yu Yang if (token->type == TOKEN_IDENTIFIER)
1082ebbfee1eSDavid Yu Yang {
1083ebbfee1eSDavid Yu Yang makeSimpleGDScriptRefTag (token, K_CLASS, GDSCRIPT_CLASS_EXTENDED, XTAG_UNKNOWN);
1084ebbfee1eSDavid Yu Yang NestingLevel *nl = nestingLevelsGetCurrent (GDScriptNestingLevels);
1085ebbfee1eSDavid Yu Yang if (nl)
1086ebbfee1eSDavid Yu Yang {
1087ebbfee1eSDavid Yu Yang tagEntryInfo *klass = getEntryInCorkQueue (nl->corkIndex);
1088ebbfee1eSDavid Yu Yang if (klass)
1089ebbfee1eSDavid Yu Yang {
1090ebbfee1eSDavid Yu Yang if (klass->extensionFields.inheritance)
1091ebbfee1eSDavid Yu Yang eFree ((void *)klass->extensionFields.inheritance);
1092ebbfee1eSDavid Yu Yang klass->extensionFields.inheritance = vStringStrdup(token->string);
1093ebbfee1eSDavid Yu Yang }
1094ebbfee1eSDavid Yu Yang }
1095ebbfee1eSDavid Yu Yang }
1096ebbfee1eSDavid Yu Yang }
1097ebbfee1eSDavid Yu Yang readToken (token);
1098ebbfee1eSDavid Yu Yang return false;
1099ebbfee1eSDavid Yu Yang }
1100ebbfee1eSDavid Yu Yang
1101ebbfee1eSDavid Yu Yang /* this only handles the most common cases, but an annotation can be any
1102ebbfee1eSDavid Yu Yang * expression in theory.
1103ebbfee1eSDavid Yu Yang * this function assumes there must be an annotation, and doesn't do any check
1104ebbfee1eSDavid Yu Yang * on the token on which it is called: the caller should do that part. */
skipVariableTypeAnnotation(tokenInfo * const token,vString * const repr)1105ebbfee1eSDavid Yu Yang static bool skipVariableTypeAnnotation (tokenInfo *const token, vString *const repr)
1106ebbfee1eSDavid Yu Yang {
1107ebbfee1eSDavid Yu Yang bool readNext = true;
1108ebbfee1eSDavid Yu Yang
1109ebbfee1eSDavid Yu Yang readToken (token);
1110ebbfee1eSDavid Yu Yang switch (token->type)
1111ebbfee1eSDavid Yu Yang {
1112ebbfee1eSDavid Yu Yang case '[': readNext = skipOverPair (token, '[', ']', repr, true); break;
1113ebbfee1eSDavid Yu Yang case '(': readNext = skipOverPair (token, '(', ')', repr, true); break;
1114ebbfee1eSDavid Yu Yang case '{': readNext = skipOverPair (token, '{', '}', repr, true); break;
1115ebbfee1eSDavid Yu Yang default: reprCat (repr, token);
1116ebbfee1eSDavid Yu Yang }
1117ebbfee1eSDavid Yu Yang if (readNext)
1118ebbfee1eSDavid Yu Yang readToken (token);
1119ebbfee1eSDavid Yu Yang /* skip subscripts and calls */
1120ebbfee1eSDavid Yu Yang while (token->type == '[' || token->type == '(' || token->type == '.' || token->type == '|')
1121ebbfee1eSDavid Yu Yang {
1122ebbfee1eSDavid Yu Yang switch (token->type)
1123ebbfee1eSDavid Yu Yang {
1124ebbfee1eSDavid Yu Yang case '[': readNext = skipOverPair (token, '[', ']', repr, true); break;
1125ebbfee1eSDavid Yu Yang case '(': readNext = skipOverPair (token, '(', ')', repr, true); break;
1126ebbfee1eSDavid Yu Yang case '|':
1127ebbfee1eSDavid Yu Yang reprCat (repr, token);
1128ebbfee1eSDavid Yu Yang skipVariableTypeAnnotation (token, repr);
1129ebbfee1eSDavid Yu Yang readNext = false;
1130ebbfee1eSDavid Yu Yang break;
1131ebbfee1eSDavid Yu Yang case '.':
1132ebbfee1eSDavid Yu Yang reprCat (repr, token);
1133ebbfee1eSDavid Yu Yang readToken (token);
1134ebbfee1eSDavid Yu Yang readNext = token->type == TOKEN_IDENTIFIER;
1135ebbfee1eSDavid Yu Yang if (readNext)
1136ebbfee1eSDavid Yu Yang reprCat (repr, token);
1137ebbfee1eSDavid Yu Yang break;
1138ebbfee1eSDavid Yu Yang default: readNext = false; break;
1139ebbfee1eSDavid Yu Yang }
1140ebbfee1eSDavid Yu Yang if (readNext)
1141ebbfee1eSDavid Yu Yang readToken (token);
1142ebbfee1eSDavid Yu Yang }
1143ebbfee1eSDavid Yu Yang
1144ebbfee1eSDavid Yu Yang return false;
1145ebbfee1eSDavid Yu Yang }
1146ebbfee1eSDavid Yu Yang
parseVariable(tokenInfo * const token,const gdscriptKind kind,const stringList * const decorators,const int keyword)1147ebbfee1eSDavid Yu Yang static bool parseVariable (tokenInfo *const token, const gdscriptKind kind,
1148ebbfee1eSDavid Yu Yang const stringList *const decorators,
1149ebbfee1eSDavid Yu Yang const int keyword)
1150ebbfee1eSDavid Yu Yang {
1151ebbfee1eSDavid Yu Yang readToken(token);
1152ebbfee1eSDavid Yu Yang vString *type = vStringNew();
1153ebbfee1eSDavid Yu Yang tokenInfo *name = newToken ();
1154ebbfee1eSDavid Yu Yang copyToken (name, token);
1155ebbfee1eSDavid Yu Yang if (!name)
1156ebbfee1eSDavid Yu Yang return false;
1157ebbfee1eSDavid Yu Yang
1158ebbfee1eSDavid Yu Yang readToken (token);
1159ebbfee1eSDavid Yu Yang // Variable declarations with dotted names are illegal
1160ebbfee1eSDavid Yu Yang if (token->type == '.')
1161ebbfee1eSDavid Yu Yang return false;
1162ebbfee1eSDavid Yu Yang
1163ebbfee1eSDavid Yu Yang /* (parse and) skip annotations. we need not to be too permissive because we
1164ebbfee1eSDavid Yu Yang * aren't yet sure we're actually parsing a variable. */
1165ebbfee1eSDavid Yu Yang if (token->type == ':' && skipVariableTypeAnnotation (token, type))
1166ebbfee1eSDavid Yu Yang readToken (token);
1167ebbfee1eSDavid Yu Yang
1168ebbfee1eSDavid Yu Yang int index = makeSimpleGDScriptTag (name, kind);
1169ebbfee1eSDavid Yu Yang deleteToken(name);
1170ebbfee1eSDavid Yu Yang tagEntryInfo *e = getEntryInCorkQueue (index);
1171ebbfee1eSDavid Yu Yang
1172ebbfee1eSDavid Yu Yang if (e && decorators && stringListCount (decorators) > 0)
1173ebbfee1eSDavid Yu Yang {
1174ebbfee1eSDavid Yu Yang vString *vstr = makeDecoratorString (decorators);
1175ebbfee1eSDavid Yu Yang attachParserField (e, true, GDScriptFields[F_ANNOTATIONS].ftype,
1176ebbfee1eSDavid Yu Yang vStringValue (vstr));
1177ebbfee1eSDavid Yu Yang vStringDelete (vstr);
1178ebbfee1eSDavid Yu Yang }
1179ebbfee1eSDavid Yu Yang
1180ebbfee1eSDavid Yu Yang vString *vtype = vStringNew();
1181ebbfee1eSDavid Yu Yang char * stype = vStringValue (type);
1182ebbfee1eSDavid Yu Yang if (strcmp(stype, "=") && strcmp(stype, ""))
1183ebbfee1eSDavid Yu Yang {
1184ebbfee1eSDavid Yu Yang vStringCatS(vtype, stype);
1185ebbfee1eSDavid Yu Yang }
1186ebbfee1eSDavid Yu Yang vStringDelete(type);
1187ebbfee1eSDavid Yu Yang
1188ebbfee1eSDavid Yu Yang if (e && vStringLength(vtype) > 0) /// TODO: Fix types away
1189ebbfee1eSDavid Yu Yang {
1190ebbfee1eSDavid Yu Yang e->extensionFields.typeRef [0] = eStrdup ("typename");
1191ebbfee1eSDavid Yu Yang e->extensionFields.typeRef [1] = vStringDeleteUnwrap (vtype);
1192ebbfee1eSDavid Yu Yang }
1193ebbfee1eSDavid Yu Yang else
1194ebbfee1eSDavid Yu Yang {
1195ebbfee1eSDavid Yu Yang vStringDelete(vtype);
1196ebbfee1eSDavid Yu Yang }
1197ebbfee1eSDavid Yu Yang
1198ebbfee1eSDavid Yu Yang
1199ebbfee1eSDavid Yu Yang while ((TokenContinuationDepth > 0 || token->type != ',') &&
1200ebbfee1eSDavid Yu Yang token->type != TOKEN_EOF &&
1201ebbfee1eSDavid Yu Yang token->type != ';' &&
1202ebbfee1eSDavid Yu Yang token->type != TOKEN_INDENT)
1203ebbfee1eSDavid Yu Yang {
1204ebbfee1eSDavid Yu Yang readToken (token);
1205ebbfee1eSDavid Yu Yang }
1206ebbfee1eSDavid Yu Yang
1207ebbfee1eSDavid Yu Yang
1208ebbfee1eSDavid Yu Yang return false;
1209ebbfee1eSDavid Yu Yang }
1210ebbfee1eSDavid Yu Yang
1211ebbfee1eSDavid Yu Yang /* pops any level >= to indent */
setIndent(tokenInfo * const token)1212ebbfee1eSDavid Yu Yang static void setIndent (tokenInfo *const token)
1213ebbfee1eSDavid Yu Yang {
1214ebbfee1eSDavid Yu Yang NestingLevel *lv = nestingLevelsGetCurrent (GDScriptNestingLevels);
1215ebbfee1eSDavid Yu Yang
1216ebbfee1eSDavid Yu Yang while (lv && GDS_NL (lv)->indentation >= token->indent)
1217ebbfee1eSDavid Yu Yang {
1218ebbfee1eSDavid Yu Yang tagEntryInfo *e = getEntryInCorkQueue (lv->corkIndex);
1219ebbfee1eSDavid Yu Yang if (e)
1220ebbfee1eSDavid Yu Yang e->extensionFields.endLine = token->lineNumber;
1221ebbfee1eSDavid Yu Yang
1222ebbfee1eSDavid Yu Yang nestingLevelsPop (GDScriptNestingLevels);
1223ebbfee1eSDavid Yu Yang lv = nestingLevelsGetCurrent (GDScriptNestingLevels);
1224ebbfee1eSDavid Yu Yang }
1225ebbfee1eSDavid Yu Yang }
1226ebbfee1eSDavid Yu Yang
prepareUnnamedClass(struct NestingLevels * nls)1227ebbfee1eSDavid Yu Yang static int prepareUnnamedClass (struct NestingLevels *nls)
1228ebbfee1eSDavid Yu Yang {
1229ebbfee1eSDavid Yu Yang {
1230ebbfee1eSDavid Yu Yang /* Ugly: we need a "position" on the input stream for making a tag.
1231ebbfee1eSDavid Yu Yang * At the begining of parsing, the position is undefined.
1232ebbfee1eSDavid Yu Yang * By reading a byte, the position is defined.
1233ebbfee1eSDavid Yu Yang */
1234ebbfee1eSDavid Yu Yang int c = getcFromInputFile ();
1235ebbfee1eSDavid Yu Yang if (c == EOF)
1236ebbfee1eSDavid Yu Yang return CORK_NIL;
1237ebbfee1eSDavid Yu Yang ungetcToInputFile (c);
1238ebbfee1eSDavid Yu Yang }
1239ebbfee1eSDavid Yu Yang
1240ebbfee1eSDavid Yu Yang vString * tmp_class = anonGenerateNew ("anon_class_", K_CLASS);
1241ebbfee1eSDavid Yu Yang int corkIndex = makeSimpleTag (tmp_class, K_CLASS);
1242ebbfee1eSDavid Yu Yang vStringDelete (tmp_class);
1243ebbfee1eSDavid Yu Yang
1244ebbfee1eSDavid Yu Yang tagEntryInfo *e = getEntryInCorkQueue (corkIndex);
1245ebbfee1eSDavid Yu Yang if (e)
1246ebbfee1eSDavid Yu Yang markTagExtraBit (e, XTAG_ANONYMOUS);
1247ebbfee1eSDavid Yu Yang
1248ebbfee1eSDavid Yu Yang /* This virtual scope should not be poped. */
1249ebbfee1eSDavid Yu Yang NestingLevel *lv = nestingLevelsPush (nls, corkIndex);
1250ebbfee1eSDavid Yu Yang GDS_NL (lv)->indentation = -1;
1251ebbfee1eSDavid Yu Yang
1252ebbfee1eSDavid Yu Yang return corkIndex;
1253ebbfee1eSDavid Yu Yang }
1254ebbfee1eSDavid Yu Yang
findGDScriptTags(void)1255ebbfee1eSDavid Yu Yang static void findGDScriptTags (void)
1256ebbfee1eSDavid Yu Yang {
1257ebbfee1eSDavid Yu Yang tokenInfo *const token = newToken ();
1258ebbfee1eSDavid Yu Yang stringList *decorators = stringListNew();
1259ebbfee1eSDavid Yu Yang bool atStatementStart = true;
1260ebbfee1eSDavid Yu Yang
1261ebbfee1eSDavid Yu Yang TokenContinuationDepth = 0;
1262ebbfee1eSDavid Yu Yang NextToken = NULL;
1263ebbfee1eSDavid Yu Yang GDScriptNestingLevels = nestingLevelsNew (sizeof (struct gdscriptNestingLevelUserData));
1264ebbfee1eSDavid Yu Yang
1265ebbfee1eSDavid Yu Yang if (isXtagEnabled (GDScriptXtagTable[X_IMPLICIT_CLASS].xtype))
1266ebbfee1eSDavid Yu Yang prepareUnnamedClass (GDScriptNestingLevels);
1267ebbfee1eSDavid Yu Yang
1268ebbfee1eSDavid Yu Yang readToken (token);
1269ebbfee1eSDavid Yu Yang while (token->type != TOKEN_EOF)
1270ebbfee1eSDavid Yu Yang {
1271ebbfee1eSDavid Yu Yang tokenType iterationTokenType = token->type;
1272ebbfee1eSDavid Yu Yang int iterationTokenKeyword = token->keyword;
1273ebbfee1eSDavid Yu Yang bool readNext = true;
1274ebbfee1eSDavid Yu Yang
1275ebbfee1eSDavid Yu Yang if (token->type == TOKEN_INDENT)
1276ebbfee1eSDavid Yu Yang setIndent (token);
1277ebbfee1eSDavid Yu Yang else if (token->keyword == KEYWORD_class ||
1278ebbfee1eSDavid Yu Yang token->keyword == KEYWORD_func ||
1279ebbfee1eSDavid Yu Yang token->keyword == KEYWORD_signal)
1280ebbfee1eSDavid Yu Yang {
1281ebbfee1eSDavid Yu Yang gdscriptKind kind = K_METHOD;
1282ebbfee1eSDavid Yu Yang switch (token->keyword)
1283ebbfee1eSDavid Yu Yang {
1284ebbfee1eSDavid Yu Yang case KEYWORD_class: kind = K_CLASS; break;
1285ebbfee1eSDavid Yu Yang case KEYWORD_func: kind = K_METHOD; break;
1286ebbfee1eSDavid Yu Yang case KEYWORD_signal: kind = K_SIGNAL; break;
1287ebbfee1eSDavid Yu Yang default:
1288ebbfee1eSDavid Yu Yang AssertNotReached();
1289ebbfee1eSDavid Yu Yang }
1290*385c6b89SMasatake YAMATO readNext = parseClassOrDef (token, decorators, kind);
1291ebbfee1eSDavid Yu Yang }
1292ebbfee1eSDavid Yu Yang else if (token->keyword == KEYWORD_extends)
1293ebbfee1eSDavid Yu Yang {
1294ebbfee1eSDavid Yu Yang readNext = parseExtends (token);
1295ebbfee1eSDavid Yu Yang }
1296ebbfee1eSDavid Yu Yang else if (token->type == '(')
1297ebbfee1eSDavid Yu Yang { /* skip parentheses to avoid finding stuff inside them */
1298ebbfee1eSDavid Yu Yang readNext = skipOverPair (token, '(', ')', NULL, false);
1299ebbfee1eSDavid Yu Yang }
1300ebbfee1eSDavid Yu Yang else if (token->keyword == KEYWORD_variable || token->keyword == KEYWORD_const)
1301ebbfee1eSDavid Yu Yang {
1302ebbfee1eSDavid Yu Yang NestingLevel *lv = nestingLevelsGetCurrent (GDScriptNestingLevels);
1303ebbfee1eSDavid Yu Yang tagEntryInfo *lvEntry = NULL;
1304ebbfee1eSDavid Yu Yang gdscriptKind kind = K_VARIABLE;
1305ebbfee1eSDavid Yu Yang
1306ebbfee1eSDavid Yu Yang if (lv)
1307ebbfee1eSDavid Yu Yang lvEntry = getEntryOfNestingLevel (lv);
1308ebbfee1eSDavid Yu Yang
1309ebbfee1eSDavid Yu Yang if (lvEntry && lvEntry->kindIndex != K_CLASS)
1310ebbfee1eSDavid Yu Yang kind = K_LOCAL_VARIABLE;
1311ebbfee1eSDavid Yu Yang
1312ebbfee1eSDavid Yu Yang if (token->keyword == KEYWORD_const)
1313ebbfee1eSDavid Yu Yang kind = K_CONST;
1314ebbfee1eSDavid Yu Yang
1315ebbfee1eSDavid Yu Yang readNext = parseVariable (token, kind, decorators, token->keyword);
1316ebbfee1eSDavid Yu Yang }
1317ebbfee1eSDavid Yu Yang else if (token->keyword == KEYWORD_enum)
1318ebbfee1eSDavid Yu Yang {
1319ebbfee1eSDavid Yu Yang readNext = parseEnum (token);
1320ebbfee1eSDavid Yu Yang }
1321ebbfee1eSDavid Yu Yang else if (token->keyword == KEYWORD_class_name)
1322ebbfee1eSDavid Yu Yang {
1323ebbfee1eSDavid Yu Yang readNext = parseClassName (token);
1324ebbfee1eSDavid Yu Yang }
1325ebbfee1eSDavid Yu Yang else if (token->type == TOKEN_KEYWORD
1326ebbfee1eSDavid Yu Yang && token->keyword == KEYWORD_modifier)
1327ebbfee1eSDavid Yu Yang {
1328ebbfee1eSDavid Yu Yang stringListAdd (decorators, vStringNewCopy(token->string));
1329ebbfee1eSDavid Yu Yang }
1330ebbfee1eSDavid Yu Yang else if (token->type == '@' && atStatementStart &&
1331ebbfee1eSDavid Yu Yang GDScriptFields[F_ANNOTATIONS].enabled)
1332ebbfee1eSDavid Yu Yang {
1333ebbfee1eSDavid Yu Yang /* collect decorators */
1334ebbfee1eSDavid Yu Yang readQualifiedName (token);
1335ebbfee1eSDavid Yu Yang if (token->type != TOKEN_IDENTIFIER
1336ebbfee1eSDavid Yu Yang && (token->keyword != KEYWORD_modifier))
1337ebbfee1eSDavid Yu Yang readNext = false;
1338ebbfee1eSDavid Yu Yang else
1339ebbfee1eSDavid Yu Yang {
1340ebbfee1eSDavid Yu Yang stringListAdd (decorators, vStringNewCopy(token->string));
1341ebbfee1eSDavid Yu Yang readToken (token);
1342ebbfee1eSDavid Yu Yang
1343ebbfee1eSDavid Yu Yang vString *d = vStringNew ();
1344ebbfee1eSDavid Yu Yang readNext = skipOverPair (token, '(', ')', d, true);
1345ebbfee1eSDavid Yu Yang if (vStringLength (d) > 0)
1346ebbfee1eSDavid Yu Yang stringListAdd (decorators, d);
1347ebbfee1eSDavid Yu Yang else
1348ebbfee1eSDavid Yu Yang vStringDelete (d);
1349ebbfee1eSDavid Yu Yang }
1350ebbfee1eSDavid Yu Yang }
1351ebbfee1eSDavid Yu Yang
1352ebbfee1eSDavid Yu Yang /* clear collected decorators for any non-decorator tokens non-indent
1353ebbfee1eSDavid Yu Yang * token. decorator collection takes care of skipping the possible
1354ebbfee1eSDavid Yu Yang * argument list, so we should never hit here parsing a decorator */
1355ebbfee1eSDavid Yu Yang if (iterationTokenType != TOKEN_INDENT &&
1356ebbfee1eSDavid Yu Yang iterationTokenType != '@' &&
1357ebbfee1eSDavid Yu Yang iterationTokenKeyword != KEYWORD_modifier &&
1358ebbfee1eSDavid Yu Yang GDScriptFields[F_ANNOTATIONS].enabled)
1359ebbfee1eSDavid Yu Yang {
1360ebbfee1eSDavid Yu Yang stringListClear (decorators);
1361ebbfee1eSDavid Yu Yang }
1362ebbfee1eSDavid Yu Yang
1363ebbfee1eSDavid Yu Yang atStatementStart = (token->type == TOKEN_INDENT || token->type == ';');
1364ebbfee1eSDavid Yu Yang
1365ebbfee1eSDavid Yu Yang if (readNext)
1366ebbfee1eSDavid Yu Yang readToken (token);
1367ebbfee1eSDavid Yu Yang }
1368ebbfee1eSDavid Yu Yang
1369ebbfee1eSDavid Yu Yang nestingLevelsFree (GDScriptNestingLevels);
1370ebbfee1eSDavid Yu Yang stringListDelete (decorators);
1371ebbfee1eSDavid Yu Yang deleteToken (token);
1372ebbfee1eSDavid Yu Yang Assert (NextToken == NULL);
1373ebbfee1eSDavid Yu Yang }
1374ebbfee1eSDavid Yu Yang
initialize(const langType language)1375ebbfee1eSDavid Yu Yang static void initialize (const langType language)
1376ebbfee1eSDavid Yu Yang {
1377ebbfee1eSDavid Yu Yang Lang_gdscript = language;
1378ebbfee1eSDavid Yu Yang
1379ebbfee1eSDavid Yu Yang TokenPool = objPoolNew (16, newPoolToken, deletePoolToken, clearPoolToken, NULL);
1380ebbfee1eSDavid Yu Yang addKeywordGroup (&modifierKeywords, language);
1381ebbfee1eSDavid Yu Yang }
1382ebbfee1eSDavid Yu Yang
finalize(langType language CTAGS_ATTR_UNUSED,bool initialized)1383ebbfee1eSDavid Yu Yang static void finalize (langType language CTAGS_ATTR_UNUSED, bool initialized)
1384ebbfee1eSDavid Yu Yang {
1385ebbfee1eSDavid Yu Yang if (!initialized)
1386ebbfee1eSDavid Yu Yang return;
1387ebbfee1eSDavid Yu Yang
1388ebbfee1eSDavid Yu Yang objPoolDelete (TokenPool);
1389ebbfee1eSDavid Yu Yang }
1390ebbfee1eSDavid Yu Yang
GDScriptParser(void)1391ebbfee1eSDavid Yu Yang extern parserDefinition* GDScriptParser (void)
1392ebbfee1eSDavid Yu Yang {
1393ebbfee1eSDavid Yu Yang static const char *const extensions[] = { "gd", NULL };
1394ebbfee1eSDavid Yu Yang parserDefinition *def = parserNew ("GDScript");
1395ebbfee1eSDavid Yu Yang def->kindTable = GDScriptKinds;
1396ebbfee1eSDavid Yu Yang def->kindCount = ARRAY_SIZE (GDScriptKinds);
1397ebbfee1eSDavid Yu Yang def->extensions = extensions;
1398ebbfee1eSDavid Yu Yang def->parser = findGDScriptTags;
1399ebbfee1eSDavid Yu Yang def->initialize = initialize;
1400ebbfee1eSDavid Yu Yang def->finalize = finalize;
1401ebbfee1eSDavid Yu Yang def->keywordTable = GDScriptKeywordTable;
1402ebbfee1eSDavid Yu Yang def->keywordCount = ARRAY_SIZE (GDScriptKeywordTable);
1403ebbfee1eSDavid Yu Yang def->fieldTable = GDScriptFields;
1404ebbfee1eSDavid Yu Yang def->fieldCount = ARRAY_SIZE (GDScriptFields);
1405ebbfee1eSDavid Yu Yang def->xtagTable = GDScriptXtagTable;
1406ebbfee1eSDavid Yu Yang def->xtagCount = ARRAY_SIZE(GDScriptXtagTable);
1407ebbfee1eSDavid Yu Yang def->useCork = CORK_QUEUE;
1408ebbfee1eSDavid Yu Yang def->requestAutomaticFQTag = true;
1409ebbfee1eSDavid Yu Yang return def;
1410ebbfee1eSDavid Yu Yang }
1411