ctags.rb 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (138) hide show
  1. data/Gemfile +2 -0
  2. data/Rakefile +23 -0
  3. data/ctags.rb.gemspec +23 -0
  4. data/ext/.gitignore +3 -0
  5. data/ext/extconf.rb +15 -0
  6. data/ext/vendor/exuberant-ctags/.gitignore +6 -0
  7. data/ext/vendor/exuberant-ctags/.indent.pro +31 -0
  8. data/ext/vendor/exuberant-ctags/COPYING +340 -0
  9. data/ext/vendor/exuberant-ctags/EXTENDING.html +386 -0
  10. data/ext/vendor/exuberant-ctags/FAQ +371 -0
  11. data/ext/vendor/exuberant-ctags/INSTALL +215 -0
  12. data/ext/vendor/exuberant-ctags/INSTALL.oth +73 -0
  13. data/ext/vendor/exuberant-ctags/MAINTAINERS +88 -0
  14. data/ext/vendor/exuberant-ctags/Makefile.in +222 -0
  15. data/ext/vendor/exuberant-ctags/NEWS +871 -0
  16. data/ext/vendor/exuberant-ctags/README +73 -0
  17. data/ext/vendor/exuberant-ctags/ant.c +42 -0
  18. data/ext/vendor/exuberant-ctags/argproc.c +505 -0
  19. data/ext/vendor/exuberant-ctags/args.c +274 -0
  20. data/ext/vendor/exuberant-ctags/args.h +63 -0
  21. data/ext/vendor/exuberant-ctags/asm.c +387 -0
  22. data/ext/vendor/exuberant-ctags/asp.c +328 -0
  23. data/ext/vendor/exuberant-ctags/awk.c +81 -0
  24. data/ext/vendor/exuberant-ctags/basic.c +203 -0
  25. data/ext/vendor/exuberant-ctags/beta.c +321 -0
  26. data/ext/vendor/exuberant-ctags/c.c +2932 -0
  27. data/ext/vendor/exuberant-ctags/cobol.c +50 -0
  28. data/ext/vendor/exuberant-ctags/config.h.in +277 -0
  29. data/ext/vendor/exuberant-ctags/configure +7704 -0
  30. data/ext/vendor/exuberant-ctags/configure.ac +532 -0
  31. data/ext/vendor/exuberant-ctags/ctags.1 +1186 -0
  32. data/ext/vendor/exuberant-ctags/ctags.h +28 -0
  33. data/ext/vendor/exuberant-ctags/ctags.html +2087 -0
  34. data/ext/vendor/exuberant-ctags/ctags.spec +40 -0
  35. data/ext/vendor/exuberant-ctags/debug.c +113 -0
  36. data/ext/vendor/exuberant-ctags/debug.h +70 -0
  37. data/ext/vendor/exuberant-ctags/descrip.mms +68 -0
  38. data/ext/vendor/exuberant-ctags/dosbatch.c +42 -0
  39. data/ext/vendor/exuberant-ctags/e_amiga.h +24 -0
  40. data/ext/vendor/exuberant-ctags/e_djgpp.h +47 -0
  41. data/ext/vendor/exuberant-ctags/e_mac.h +143 -0
  42. data/ext/vendor/exuberant-ctags/e_msoft.h +76 -0
  43. data/ext/vendor/exuberant-ctags/e_os2.h +37 -0
  44. data/ext/vendor/exuberant-ctags/e_qdos.h +34 -0
  45. data/ext/vendor/exuberant-ctags/e_riscos.h +58 -0
  46. data/ext/vendor/exuberant-ctags/e_vms.h +31 -0
  47. data/ext/vendor/exuberant-ctags/eiffel.c +1352 -0
  48. data/ext/vendor/exuberant-ctags/entry.c +847 -0
  49. data/ext/vendor/exuberant-ctags/entry.h +103 -0
  50. data/ext/vendor/exuberant-ctags/erlang.c +189 -0
  51. data/ext/vendor/exuberant-ctags/flex.c +2243 -0
  52. data/ext/vendor/exuberant-ctags/fortran.c +2197 -0
  53. data/ext/vendor/exuberant-ctags/general.h +127 -0
  54. data/ext/vendor/exuberant-ctags/get.c +669 -0
  55. data/ext/vendor/exuberant-ctags/get.h +50 -0
  56. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/all-wcprops +47 -0
  57. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/entries +112 -0
  58. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/README.txt.svn-base +5 -0
  59. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regcomp.c.svn-base +3818 -0
  60. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regex.c.svn-base +74 -0
  61. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regex.h.svn-base +575 -0
  62. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regex_internal.c.svn-base +1713 -0
  63. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regex_internal.h.svn-base +773 -0
  64. data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regexec.c.svn-base +4338 -0
  65. data/ext/vendor/exuberant-ctags/gnu_regex/README.txt +5 -0
  66. data/ext/vendor/exuberant-ctags/gnu_regex/regcomp.c +3818 -0
  67. data/ext/vendor/exuberant-ctags/gnu_regex/regex.c +74 -0
  68. data/ext/vendor/exuberant-ctags/gnu_regex/regex.h +575 -0
  69. data/ext/vendor/exuberant-ctags/gnu_regex/regex_internal.c +1713 -0
  70. data/ext/vendor/exuberant-ctags/gnu_regex/regex_internal.h +773 -0
  71. data/ext/vendor/exuberant-ctags/gnu_regex/regexec.c +4338 -0
  72. data/ext/vendor/exuberant-ctags/html.c +49 -0
  73. data/ext/vendor/exuberant-ctags/jscript.c +1572 -0
  74. data/ext/vendor/exuberant-ctags/keyword.c +258 -0
  75. data/ext/vendor/exuberant-ctags/keyword.h +34 -0
  76. data/ext/vendor/exuberant-ctags/lisp.c +139 -0
  77. data/ext/vendor/exuberant-ctags/lregex.c +704 -0
  78. data/ext/vendor/exuberant-ctags/lua.c +133 -0
  79. data/ext/vendor/exuberant-ctags/mac.c +273 -0
  80. data/ext/vendor/exuberant-ctags/magic.diff +21 -0
  81. data/ext/vendor/exuberant-ctags/main.c +584 -0
  82. data/ext/vendor/exuberant-ctags/main.h +32 -0
  83. data/ext/vendor/exuberant-ctags/maintainer.mak +476 -0
  84. data/ext/vendor/exuberant-ctags/make.c +217 -0
  85. data/ext/vendor/exuberant-ctags/matlab.c +44 -0
  86. data/ext/vendor/exuberant-ctags/mk_bc3.mak +46 -0
  87. data/ext/vendor/exuberant-ctags/mk_bc5.mak +49 -0
  88. data/ext/vendor/exuberant-ctags/mk_djg.mak +18 -0
  89. data/ext/vendor/exuberant-ctags/mk_manx.mak +65 -0
  90. data/ext/vendor/exuberant-ctags/mk_mingw.mak +31 -0
  91. data/ext/vendor/exuberant-ctags/mk_mpw.mak +130 -0
  92. data/ext/vendor/exuberant-ctags/mk_mvc.mak +40 -0
  93. data/ext/vendor/exuberant-ctags/mk_os2.mak +104 -0
  94. data/ext/vendor/exuberant-ctags/mk_qdos.mak +100 -0
  95. data/ext/vendor/exuberant-ctags/mk_sas.mak +63 -0
  96. data/ext/vendor/exuberant-ctags/mkinstalldirs +40 -0
  97. data/ext/vendor/exuberant-ctags/ocaml.c +1842 -0
  98. data/ext/vendor/exuberant-ctags/options.c +1842 -0
  99. data/ext/vendor/exuberant-ctags/options.h +155 -0
  100. data/ext/vendor/exuberant-ctags/parse.c +677 -0
  101. data/ext/vendor/exuberant-ctags/parse.h +129 -0
  102. data/ext/vendor/exuberant-ctags/parsers.h +63 -0
  103. data/ext/vendor/exuberant-ctags/pascal.c +267 -0
  104. data/ext/vendor/exuberant-ctags/perl.c +382 -0
  105. data/ext/vendor/exuberant-ctags/php.c +237 -0
  106. data/ext/vendor/exuberant-ctags/python.c +771 -0
  107. data/ext/vendor/exuberant-ctags/qdos.c +106 -0
  108. data/ext/vendor/exuberant-ctags/read.c +569 -0
  109. data/ext/vendor/exuberant-ctags/read.h +116 -0
  110. data/ext/vendor/exuberant-ctags/readtags.c +959 -0
  111. data/ext/vendor/exuberant-ctags/readtags.h +252 -0
  112. data/ext/vendor/exuberant-ctags/rexx.c +39 -0
  113. data/ext/vendor/exuberant-ctags/routines.c +891 -0
  114. data/ext/vendor/exuberant-ctags/routines.h +134 -0
  115. data/ext/vendor/exuberant-ctags/ruby.c +408 -0
  116. data/ext/vendor/exuberant-ctags/scheme.c +111 -0
  117. data/ext/vendor/exuberant-ctags/sh.c +115 -0
  118. data/ext/vendor/exuberant-ctags/slang.c +41 -0
  119. data/ext/vendor/exuberant-ctags/sml.c +212 -0
  120. data/ext/vendor/exuberant-ctags/sort.c +230 -0
  121. data/ext/vendor/exuberant-ctags/sort.h +32 -0
  122. data/ext/vendor/exuberant-ctags/source.mak +122 -0
  123. data/ext/vendor/exuberant-ctags/sql.c +2112 -0
  124. data/ext/vendor/exuberant-ctags/strlist.c +281 -0
  125. data/ext/vendor/exuberant-ctags/strlist.h +54 -0
  126. data/ext/vendor/exuberant-ctags/tcl.c +116 -0
  127. data/ext/vendor/exuberant-ctags/tex.c +524 -0
  128. data/ext/vendor/exuberant-ctags/verilog.c +340 -0
  129. data/ext/vendor/exuberant-ctags/vhdl.c +835 -0
  130. data/ext/vendor/exuberant-ctags/vim.c +636 -0
  131. data/ext/vendor/exuberant-ctags/vstring.c +232 -0
  132. data/ext/vendor/exuberant-ctags/vstring.h +85 -0
  133. data/ext/vendor/exuberant-ctags/yacc.c +40 -0
  134. data/lib/ctags/exuberant.rb +45 -0
  135. data/lib/ctags/version.rb +3 -0
  136. data/lib/ctags.rb +6 -0
  137. data/test/test_ctags.rb +24 -0
  138. metadata +233 -0
@@ -0,0 +1,2243 @@
1
+ /*
2
+ * $Id: flex.c 666 2008-05-15 17:47:31Z dfishburn $
3
+ *
4
+ * Copyright (c) 2008, David Fishburn
5
+ *
6
+ * This source code is released for free distribution under the terms of the
7
+ * GNU General Public License.
8
+ *
9
+ * This module contains functions for generating tags for Adobe languages.
10
+ * There are a number of different ones, but this will begin with:
11
+ * Flex
12
+ * MXML files (*.mMacromedia XML)
13
+ * ActionScript files (*.as)
14
+ *
15
+ * Flex 3 language reference
16
+ * http://livedocs.adobe.com/flex/3/langref/index.html
17
+ */
18
+
19
+ /*
20
+ * INCLUDE FILES
21
+ */
22
+ #include "general.h" /* must always come first */
23
+ #include <ctype.h> /* to define isalpha () */
24
+ #include <setjmp.h>
25
+ #ifdef DEBUG
26
+ #include <stdio.h>
27
+ #endif
28
+
29
+ #include "debug.h"
30
+ #include "entry.h"
31
+ #include "keyword.h"
32
+ #include "parse.h"
33
+ #include "read.h"
34
+ #include "routines.h"
35
+ #include "vstring.h"
36
+
37
+ /*
38
+ * MACROS
39
+ */
40
+ #define isType(token,t) (boolean) ((token)->type == (t))
41
+ #define isKeyword(token,k) (boolean) ((token)->keyword == (k))
42
+
43
+ /*
44
+ * DATA DECLARATIONS
45
+ */
46
+
47
+ typedef enum eException { ExceptionNone, ExceptionEOF } exception_t;
48
+
49
+ /*
50
+ * Tracks class and function names already created
51
+ */
52
+ static stringList *ClassNames;
53
+ static stringList *FunctionNames;
54
+
55
+ /* Used to specify type of keyword.
56
+ */
57
+ typedef enum eKeywordId {
58
+ KEYWORD_NONE = -1,
59
+ KEYWORD_function,
60
+ KEYWORD_capital_function,
61
+ KEYWORD_object,
62
+ KEYWORD_capital_object,
63
+ KEYWORD_prototype,
64
+ KEYWORD_var,
65
+ KEYWORD_new,
66
+ KEYWORD_this,
67
+ KEYWORD_for,
68
+ KEYWORD_while,
69
+ KEYWORD_do,
70
+ KEYWORD_if,
71
+ KEYWORD_else,
72
+ KEYWORD_switch,
73
+ KEYWORD_try,
74
+ KEYWORD_catch,
75
+ KEYWORD_finally,
76
+ KEYWORD_public,
77
+ KEYWORD_private,
78
+ KEYWORD_static,
79
+ KEYWORD_class,
80
+ KEYWORD_id,
81
+ KEYWORD_script,
82
+ KEYWORD_cdata,
83
+ KEYWORD_mx
84
+ } keywordId;
85
+
86
+ /* Used to determine whether keyword is valid for the token language and
87
+ * what its ID is.
88
+ */
89
+ typedef struct sKeywordDesc {
90
+ const char *name;
91
+ keywordId id;
92
+ } keywordDesc;
93
+
94
+ typedef enum eTokenType {
95
+ TOKEN_UNDEFINED,
96
+ TOKEN_CHARACTER,
97
+ TOKEN_CLOSE_PAREN,
98
+ TOKEN_SEMICOLON,
99
+ TOKEN_COLON,
100
+ TOKEN_COMMA,
101
+ TOKEN_KEYWORD,
102
+ TOKEN_OPEN_PAREN,
103
+ TOKEN_OPERATOR,
104
+ TOKEN_IDENTIFIER,
105
+ TOKEN_STRING,
106
+ TOKEN_PERIOD,
107
+ TOKEN_OPEN_CURLY,
108
+ TOKEN_CLOSE_CURLY,
109
+ TOKEN_EQUAL_SIGN,
110
+ TOKEN_EXCLAMATION,
111
+ TOKEN_FORWARD_SLASH,
112
+ TOKEN_OPEN_SQUARE,
113
+ TOKEN_CLOSE_SQUARE,
114
+ TOKEN_OPEN_MXML,
115
+ TOKEN_CLOSE_MXML,
116
+ TOKEN_CLOSE_SGML,
117
+ TOKEN_LESS_THAN,
118
+ TOKEN_GREATER_THAN,
119
+ TOKEN_QUESTION_MARK
120
+ } tokenType;
121
+
122
+ typedef struct sTokenInfo {
123
+ tokenType type;
124
+ keywordId keyword;
125
+ vString * string;
126
+ vString * scope;
127
+ unsigned long lineNumber;
128
+ fpos_t filePosition;
129
+ int nestLevel;
130
+ boolean ignoreTag;
131
+ boolean isClass;
132
+ } tokenInfo;
133
+
134
+ /*
135
+ * DATA DEFINITIONS
136
+ */
137
+
138
+ static langType Lang_js;
139
+
140
+ static jmp_buf Exception;
141
+
142
+ typedef enum {
143
+ FLEXTAG_FUNCTION,
144
+ FLEXTAG_CLASS,
145
+ FLEXTAG_METHOD,
146
+ FLEXTAG_PROPERTY,
147
+ FLEXTAG_VARIABLE,
148
+ FLEXTAG_MXTAG,
149
+ FLEXTAG_COUNT
150
+ } flexKind;
151
+
152
+ static kindOption FlexKinds [] = {
153
+ { TRUE, 'f', "function", "functions" },
154
+ { TRUE, 'c', "class", "classes" },
155
+ { TRUE, 'm', "method", "methods" },
156
+ { TRUE, 'p', "property", "properties" },
157
+ { TRUE, 'v', "variable", "global variables" },
158
+ { TRUE, 'x', "mxtag", "mxtags" }
159
+ };
160
+
161
+ static const keywordDesc FlexKeywordTable [] = {
162
+ /* keyword keyword ID */
163
+ { "function", KEYWORD_function },
164
+ { "Function", KEYWORD_capital_function },
165
+ { "object", KEYWORD_object },
166
+ { "Object", KEYWORD_capital_object },
167
+ { "prototype", KEYWORD_prototype },
168
+ { "var", KEYWORD_var },
169
+ { "new", KEYWORD_new },
170
+ { "this", KEYWORD_this },
171
+ { "for", KEYWORD_for },
172
+ { "while", KEYWORD_while },
173
+ { "do", KEYWORD_do },
174
+ { "if", KEYWORD_if },
175
+ { "else", KEYWORD_else },
176
+ { "switch", KEYWORD_switch },
177
+ { "try", KEYWORD_try },
178
+ { "catch", KEYWORD_catch },
179
+ { "finally", KEYWORD_finally },
180
+ { "public", KEYWORD_public },
181
+ { "private", KEYWORD_private },
182
+ { "static", KEYWORD_static },
183
+ { "class", KEYWORD_class },
184
+ { "id", KEYWORD_id },
185
+ { "script", KEYWORD_script },
186
+ { "cdata", KEYWORD_cdata },
187
+ { "mx", KEYWORD_mx }
188
+ };
189
+
190
+ /*
191
+ * FUNCTION DEFINITIONS
192
+ */
193
+
194
+ /* Recursive functions */
195
+ static void parseFunction (tokenInfo *const token);
196
+ static boolean parseBlock (tokenInfo *const token, tokenInfo *const parent);
197
+ static boolean parseLine (tokenInfo *const token);
198
+ static boolean parseActionScript (tokenInfo *const token);
199
+
200
+ static boolean isIdentChar (const int c)
201
+ {
202
+ return (boolean)
203
+ (isalpha (c) || isdigit (c) || c == '$' ||
204
+ c == '@' || c == '_' || c == '#');
205
+ }
206
+
207
+ static void buildFlexKeywordHash (void)
208
+ {
209
+ const size_t count = sizeof (FlexKeywordTable) /
210
+ sizeof (FlexKeywordTable [0]);
211
+ size_t i;
212
+ for (i = 0 ; i < count ; ++i)
213
+ {
214
+ const keywordDesc* const p = &FlexKeywordTable [i];
215
+ addKeyword (p->name, Lang_js, (int) p->id);
216
+ }
217
+ }
218
+
219
+ static tokenInfo *newToken (void)
220
+ {
221
+ tokenInfo *const token = xMalloc (1, tokenInfo);
222
+
223
+ token->type = TOKEN_UNDEFINED;
224
+ token->keyword = KEYWORD_NONE;
225
+ token->string = vStringNew ();
226
+ token->scope = vStringNew ();
227
+ token->nestLevel = 0;
228
+ token->isClass = FALSE;
229
+ token->ignoreTag = FALSE;
230
+ token->lineNumber = getSourceLineNumber ();
231
+ token->filePosition = getInputFilePosition ();
232
+
233
+ return token;
234
+ }
235
+
236
+ static void deleteToken (tokenInfo *const token)
237
+ {
238
+ vStringDelete (token->string);
239
+ vStringDelete (token->scope);
240
+ eFree (token);
241
+ }
242
+
243
+ /*
244
+ * Tag generation functions
245
+ */
246
+
247
+ static void makeConstTag (tokenInfo *const token, const flexKind kind)
248
+ {
249
+ if (FlexKinds [kind].enabled && ! token->ignoreTag )
250
+ {
251
+ const char *const name = vStringValue (token->string);
252
+ tagEntryInfo e;
253
+ initTagEntry (&e, name);
254
+
255
+ e.lineNumber = token->lineNumber;
256
+ e.filePosition = token->filePosition;
257
+ e.kindName = FlexKinds [kind].name;
258
+ e.kind = FlexKinds [kind].letter;
259
+
260
+ makeTagEntry (&e);
261
+ }
262
+ }
263
+
264
+ static void makeFlexTag (tokenInfo *const token, flexKind kind)
265
+ {
266
+ vString * fulltag;
267
+
268
+ if (FlexKinds [kind].enabled && ! token->ignoreTag )
269
+ {
270
+ DebugStatement (
271
+ debugPrintf (DEBUG_PARSE
272
+ , "\n makeFlexTag start: token isClass:%d scope:%s name:%s\n"
273
+ , token->isClass
274
+ , vStringValue(token->scope)
275
+ , vStringValue(token->string)
276
+ );
277
+ );
278
+ if (kind == FLEXTAG_FUNCTION && token->isClass )
279
+ {
280
+ kind = FLEXTAG_METHOD;
281
+ }
282
+ /*
283
+ * If a scope has been added to the token, change the token
284
+ * string to include the scope when making the tag.
285
+ */
286
+ if ( vStringLength(token->scope) > 0 )
287
+ {
288
+ fulltag = vStringNew ();
289
+ vStringCopy(fulltag, token->scope);
290
+ vStringCatS (fulltag, ".");
291
+ vStringCatS (fulltag, vStringValue(token->string));
292
+ vStringTerminate(fulltag);
293
+ vStringCopy(token->string, fulltag);
294
+ vStringDelete (fulltag);
295
+ }
296
+ makeConstTag (token, kind);
297
+ }
298
+ }
299
+
300
+ static void makeClassTag (tokenInfo *const token)
301
+ {
302
+ vString * fulltag;
303
+
304
+ if ( ! token->ignoreTag )
305
+ {
306
+ fulltag = vStringNew ();
307
+ if (vStringLength (token->scope) > 0)
308
+ {
309
+ vStringCopy(fulltag, token->scope);
310
+ vStringCatS (fulltag, ".");
311
+ vStringCatS (fulltag, vStringValue(token->string));
312
+ }
313
+ else
314
+ {
315
+ vStringCopy(fulltag, token->string);
316
+ }
317
+ vStringTerminate(fulltag);
318
+ if ( ! stringListHas(ClassNames, vStringValue (fulltag)) )
319
+ {
320
+ stringListAdd (ClassNames, vStringNewCopy (fulltag));
321
+ makeFlexTag (token, FLEXTAG_CLASS);
322
+ }
323
+ vStringDelete (fulltag);
324
+ }
325
+ }
326
+
327
+ static void makeMXTag (tokenInfo *const token)
328
+ {
329
+ vString * fulltag;
330
+
331
+ if ( ! token->ignoreTag )
332
+ {
333
+ fulltag = vStringNew ();
334
+ if (vStringLength (token->scope) > 0)
335
+ {
336
+ vStringCopy(fulltag, token->scope);
337
+ vStringCatS (fulltag, ".");
338
+ vStringCatS (fulltag, vStringValue(token->string));
339
+ }
340
+ else
341
+ {
342
+ vStringCopy(fulltag, token->string);
343
+ }
344
+ vStringTerminate(fulltag);
345
+ makeFlexTag (token, FLEXTAG_MXTAG);
346
+ vStringDelete (fulltag);
347
+ }
348
+ }
349
+
350
+ static void makeFunctionTag (tokenInfo *const token)
351
+ {
352
+ vString * fulltag;
353
+
354
+ if ( ! token->ignoreTag )
355
+ {
356
+ fulltag = vStringNew ();
357
+ if (vStringLength (token->scope) > 0)
358
+ {
359
+ vStringCopy(fulltag, token->scope);
360
+ vStringCatS (fulltag, ".");
361
+ vStringCatS (fulltag, vStringValue(token->string));
362
+ }
363
+ else
364
+ {
365
+ vStringCopy(fulltag, token->string);
366
+ }
367
+ vStringTerminate(fulltag);
368
+ if ( ! stringListHas(FunctionNames, vStringValue (fulltag)) )
369
+ {
370
+ stringListAdd (FunctionNames, vStringNewCopy (fulltag));
371
+ makeFlexTag (token, FLEXTAG_FUNCTION);
372
+ }
373
+ vStringDelete (fulltag);
374
+ }
375
+ }
376
+
377
+ /*
378
+ * Parsing functions
379
+ */
380
+
381
+ static void parseString (vString *const string, const int delimiter)
382
+ {
383
+ boolean end = FALSE;
384
+ while (! end)
385
+ {
386
+ int c = fileGetc ();
387
+ if (c == EOF)
388
+ end = TRUE;
389
+ else if (c == '\\')
390
+ {
391
+ c = fileGetc(); /* This maybe a ' or ". */
392
+ vStringPut(string, c);
393
+ }
394
+ else if (c == delimiter)
395
+ end = TRUE;
396
+ else
397
+ vStringPut (string, c);
398
+ }
399
+ vStringTerminate (string);
400
+ }
401
+
402
+ /* Read a C identifier beginning with "firstChar" and places it into
403
+ * "name".
404
+ */
405
+ static void parseIdentifier (vString *const string, const int firstChar)
406
+ {
407
+ int c = firstChar;
408
+ Assert (isIdentChar (c));
409
+ do
410
+ {
411
+ vStringPut (string, c);
412
+ c = fileGetc ();
413
+ } while (isIdentChar (c));
414
+ vStringTerminate (string);
415
+ if (!isspace (c))
416
+ fileUngetc (c); /* unget non-identifier character */
417
+ }
418
+
419
+ static void readToken (tokenInfo *const token)
420
+ {
421
+ int c;
422
+
423
+ token->type = TOKEN_UNDEFINED;
424
+ token->keyword = KEYWORD_NONE;
425
+ vStringClear (token->string);
426
+
427
+ getNextChar:
428
+ do
429
+ {
430
+ c = fileGetc ();
431
+ token->lineNumber = getSourceLineNumber ();
432
+ token->filePosition = getInputFilePosition ();
433
+ }
434
+ while (c == '\t' || c == ' ' || c == '\n');
435
+
436
+ switch (c)
437
+ {
438
+ case EOF: longjmp (Exception, (int)ExceptionEOF); break;
439
+ case '(': token->type = TOKEN_OPEN_PAREN; break;
440
+ case ')': token->type = TOKEN_CLOSE_PAREN; break;
441
+ case ';': token->type = TOKEN_SEMICOLON; break;
442
+ case ',': token->type = TOKEN_COMMA; break;
443
+ case '.': token->type = TOKEN_PERIOD; break;
444
+ case ':': token->type = TOKEN_COLON; break;
445
+ case '{': token->type = TOKEN_OPEN_CURLY; break;
446
+ case '}': token->type = TOKEN_CLOSE_CURLY; break;
447
+ case '=': token->type = TOKEN_EQUAL_SIGN; break;
448
+ case '[': token->type = TOKEN_OPEN_SQUARE; break;
449
+ case ']': token->type = TOKEN_CLOSE_SQUARE; break;
450
+ case '?': token->type = TOKEN_QUESTION_MARK; break;
451
+
452
+ case '\'':
453
+ case '"':
454
+ token->type = TOKEN_STRING;
455
+ parseString (token->string, c);
456
+ token->lineNumber = getSourceLineNumber ();
457
+ token->filePosition = getInputFilePosition ();
458
+ break;
459
+
460
+ case '\\':
461
+ c = fileGetc ();
462
+ if (c != '\\' && c != '"' && !isspace (c))
463
+ fileUngetc (c);
464
+ token->type = TOKEN_CHARACTER;
465
+ token->lineNumber = getSourceLineNumber ();
466
+ token->filePosition = getInputFilePosition ();
467
+ break;
468
+
469
+ case '/':
470
+ {
471
+ int d = fileGetc ();
472
+ if ( (d != '*') && /* is this the start of a comment? */
473
+ (d != '/') && /* is a one line comment? */
474
+ (d != '>') ) /* is this a close XML tag? */
475
+ {
476
+ fileUngetc (d);
477
+ token->type = TOKEN_FORWARD_SLASH;
478
+ token->lineNumber = getSourceLineNumber ();
479
+ token->filePosition = getInputFilePosition ();
480
+ }
481
+ else
482
+ {
483
+ if (d == '*')
484
+ {
485
+ do
486
+ {
487
+ fileSkipToCharacter ('*');
488
+ c = fileGetc ();
489
+ if (c == '/')
490
+ break;
491
+ else
492
+ fileUngetc (c);
493
+ } while (c != EOF && c != '\0');
494
+ goto getNextChar;
495
+ }
496
+ else if (d == '/') /* is this the start of a comment? */
497
+ {
498
+ fileSkipToCharacter ('\n');
499
+ goto getNextChar;
500
+ }
501
+ else if (d == '>') /* is this the start of a comment? */
502
+ {
503
+ token->type = TOKEN_CLOSE_SGML;
504
+ token->lineNumber = getSourceLineNumber ();
505
+ token->filePosition = getInputFilePosition ();
506
+ }
507
+ }
508
+ break;
509
+ }
510
+
511
+ case '<':
512
+ {
513
+ /*
514
+ * An XML comment looks like this
515
+ * <!-- anything over multiple lines -->
516
+ */
517
+ int d = fileGetc ();
518
+
519
+ if ( (d != '!' ) && /* is this the start of a comment? */
520
+ (d != '/' ) && /* is this the start of a closing mx tag */
521
+ (d != 'm' ) ) /* is this the start of a mx tag */
522
+ {
523
+ fileUngetc (d);
524
+ token->type = TOKEN_LESS_THAN;
525
+ token->lineNumber = getSourceLineNumber ();
526
+ token->filePosition = getInputFilePosition ();
527
+
528
+ }
529
+ else
530
+ {
531
+ if (d == '!')
532
+ {
533
+ int e = fileGetc ();
534
+ if ( e != '-' ) /* is this the start of a comment? */
535
+ {
536
+ fileUngetc (e);
537
+ fileUngetc (d);
538
+ token->type = TOKEN_LESS_THAN;
539
+ token->lineNumber = getSourceLineNumber ();
540
+ token->filePosition = getInputFilePosition ();
541
+ }
542
+ else
543
+ {
544
+ if (e == '-')
545
+ {
546
+ int f = fileGetc ();
547
+ if ( f != '-' ) /* is this the start of a comment? */
548
+ {
549
+ fileUngetc (f);
550
+ fileUngetc (e);
551
+ fileUngetc (d);
552
+ token->type = TOKEN_LESS_THAN;
553
+ token->lineNumber = getSourceLineNumber ();
554
+ token->filePosition = getInputFilePosition ();
555
+ }
556
+ else
557
+ {
558
+ if (f == '-')
559
+ {
560
+ do
561
+ {
562
+ fileSkipToCharacter ('-');
563
+ c = fileGetc ();
564
+ if (c == '-')
565
+ {
566
+ d = fileGetc ();
567
+ if (d == '>')
568
+ break;
569
+ else
570
+ {
571
+ fileUngetc (d);
572
+ fileUngetc (c);
573
+ }
574
+ break;
575
+ }
576
+ else
577
+ fileUngetc (c);
578
+ } while (c != EOF && c != '\0');
579
+ goto getNextChar;
580
+ }
581
+ }
582
+ }
583
+ }
584
+ }
585
+ else if (d == 'm')
586
+ {
587
+ int e = fileGetc ();
588
+ if ( e != 'x' ) /* continuing an mx tag */
589
+ {
590
+ fileUngetc (e);
591
+ fileUngetc (d);
592
+ token->type = TOKEN_LESS_THAN;
593
+ token->lineNumber = getSourceLineNumber ();
594
+ token->filePosition = getInputFilePosition ();
595
+ }
596
+ else
597
+ {
598
+ if (e == 'x')
599
+ {
600
+ int f = fileGetc ();
601
+ if ( f != ':' ) /* is this the start of a comment? */
602
+ {
603
+ fileUngetc (f);
604
+ fileUngetc (e);
605
+ fileUngetc (d);
606
+ token->type = TOKEN_LESS_THAN;
607
+ token->lineNumber = getSourceLineNumber ();
608
+ token->filePosition = getInputFilePosition ();
609
+ }
610
+ else
611
+ {
612
+ if (f == ':')
613
+ {
614
+ token->type = TOKEN_OPEN_MXML;
615
+ token->lineNumber = getSourceLineNumber ();
616
+ token->filePosition = getInputFilePosition ();
617
+ }
618
+ }
619
+ }
620
+ }
621
+ }
622
+ else if (d == '/')
623
+ {
624
+ int e = fileGetc ();
625
+ if ( e != 'm' ) /* continuing an mx tag */
626
+ {
627
+ fileUngetc (e);
628
+ fileUngetc (d);
629
+ token->type = TOKEN_LESS_THAN;
630
+ token->lineNumber = getSourceLineNumber ();
631
+ token->filePosition = getInputFilePosition ();
632
+ }
633
+ else
634
+ {
635
+ int f = fileGetc ();
636
+ if ( f != 'x' ) /* continuing an mx tag */
637
+ {
638
+ fileUngetc (f);
639
+ fileUngetc (e);
640
+ token->type = TOKEN_LESS_THAN;
641
+ token->lineNumber = getSourceLineNumber ();
642
+ token->filePosition = getInputFilePosition ();
643
+ }
644
+ else
645
+ {
646
+ if (f == 'x')
647
+ {
648
+ int g = fileGetc ();
649
+ if ( g != ':' ) /* is this the start of a comment? */
650
+ {
651
+ fileUngetc (g);
652
+ fileUngetc (f);
653
+ fileUngetc (e);
654
+ token->type = TOKEN_LESS_THAN;
655
+ token->lineNumber = getSourceLineNumber ();
656
+ token->filePosition = getInputFilePosition ();
657
+ }
658
+ else
659
+ {
660
+ if (g == ':')
661
+ {
662
+ token->type = TOKEN_CLOSE_MXML;
663
+ token->lineNumber = getSourceLineNumber ();
664
+ token->filePosition = getInputFilePosition ();
665
+ }
666
+ }
667
+ }
668
+ }
669
+ }
670
+ }
671
+ }
672
+ break;
673
+ }
674
+
675
+ case '>':
676
+ token->type = TOKEN_GREATER_THAN;
677
+ token->lineNumber = getSourceLineNumber ();
678
+ token->filePosition = getInputFilePosition ();
679
+ break;
680
+
681
+ case '!':
682
+ token->type = TOKEN_EXCLAMATION;
683
+ /*token->lineNumber = getSourceLineNumber ();
684
+ token->filePosition = getInputFilePosition ();*/
685
+ break;
686
+
687
+ default:
688
+ if (! isIdentChar (c))
689
+ token->type = TOKEN_UNDEFINED;
690
+ else
691
+ {
692
+ parseIdentifier (token->string, c);
693
+ token->lineNumber = getSourceLineNumber ();
694
+ token->filePosition = getInputFilePosition ();
695
+ token->keyword = analyzeToken (token->string, Lang_js);
696
+ if (isKeyword (token, KEYWORD_NONE))
697
+ token->type = TOKEN_IDENTIFIER;
698
+ else
699
+ token->type = TOKEN_KEYWORD;
700
+ }
701
+ break;
702
+ }
703
+ }
704
+
705
+ static void copyToken (tokenInfo *const dest, tokenInfo *const src)
706
+ {
707
+ dest->nestLevel = src->nestLevel;
708
+ dest->lineNumber = src->lineNumber;
709
+ dest->filePosition = src->filePosition;
710
+ dest->type = src->type;
711
+ dest->keyword = src->keyword;
712
+ dest->isClass = src->isClass;
713
+ vStringCopy(dest->string, src->string);
714
+ vStringCopy(dest->scope, src->scope);
715
+ }
716
+
717
+ /*
718
+ * Token parsing functions
719
+ */
720
+
721
+ static void skipArgumentList (tokenInfo *const token)
722
+ {
723
+ int nest_level = 0;
724
+
725
+ /*
726
+ * Other databases can have arguments with fully declared
727
+ * datatypes:
728
+ * ( name varchar(30), text binary(10) )
729
+ * So we must check for nested open and closing parantheses
730
+ */
731
+
732
+ if (isType (token, TOKEN_OPEN_PAREN)) /* arguments? */
733
+ {
734
+ nest_level++;
735
+ while (! (isType (token, TOKEN_CLOSE_PAREN) && (nest_level == 0)))
736
+ {
737
+ readToken (token);
738
+ if (isType (token, TOKEN_OPEN_PAREN))
739
+ {
740
+ nest_level++;
741
+ }
742
+ if (isType (token, TOKEN_CLOSE_PAREN))
743
+ {
744
+ if (nest_level > 0)
745
+ {
746
+ nest_level--;
747
+ }
748
+ }
749
+ }
750
+ readToken (token);
751
+ }
752
+ }
753
+
754
+ static void skipArrayList (tokenInfo *const token)
755
+ {
756
+ int nest_level = 0;
757
+
758
+ /*
759
+ * Handle square brackets
760
+ * var name[1]
761
+ * So we must check for nested open and closing square brackets
762
+ */
763
+
764
+ if (isType (token, TOKEN_OPEN_SQUARE)) /* arguments? */
765
+ {
766
+ nest_level++;
767
+ while (! (isType (token, TOKEN_CLOSE_SQUARE) && (nest_level == 0)))
768
+ {
769
+ readToken (token);
770
+ if (isType (token, TOKEN_OPEN_SQUARE))
771
+ {
772
+ nest_level++;
773
+ }
774
+ if (isType (token, TOKEN_CLOSE_SQUARE))
775
+ {
776
+ if (nest_level > 0)
777
+ {
778
+ nest_level--;
779
+ }
780
+ }
781
+ }
782
+ readToken (token);
783
+ }
784
+ }
785
+
786
+ static void addContext (tokenInfo* const parent, const tokenInfo* const child)
787
+ {
788
+ if (vStringLength (parent->string) > 0)
789
+ {
790
+ vStringCatS (parent->string, ".");
791
+ }
792
+ vStringCatS (parent->string, vStringValue(child->string));
793
+ vStringTerminate(parent->string);
794
+ }
795
+
796
+ static void addToScope (tokenInfo* const token, vString* const extra)
797
+ {
798
+ if (vStringLength (token->scope) > 0)
799
+ {
800
+ vStringCatS (token->scope, ".");
801
+ }
802
+ vStringCatS (token->scope, vStringValue(extra));
803
+ vStringTerminate(token->scope);
804
+ }
805
+
806
+ /*
807
+ * Scanning functions
808
+ */
809
+
810
+ static void findCmdTerm (tokenInfo *const token)
811
+ {
812
+ /*
813
+ * Read until we find either a semicolon or closing brace.
814
+ * Any nested braces will be handled within.
815
+ */
816
+ while (! ( isType (token, TOKEN_SEMICOLON) ||
817
+ isType (token, TOKEN_CLOSE_CURLY) ) )
818
+ {
819
+ /* Handle nested blocks */
820
+ if ( isType (token, TOKEN_OPEN_CURLY))
821
+ {
822
+ parseBlock (token, token);
823
+ }
824
+ else if ( isType (token, TOKEN_OPEN_PAREN) )
825
+ {
826
+ skipArgumentList(token);
827
+ }
828
+ else
829
+ {
830
+ readToken (token);
831
+ }
832
+ }
833
+ }
834
+
835
+ static void parseSwitch (tokenInfo *const token)
836
+ {
837
+ /*
838
+ * switch (expression){
839
+ * case value1:
840
+ * statement;
841
+ * break;
842
+ * case value2:
843
+ * statement;
844
+ * break;
845
+ * default : statement;
846
+ * }
847
+ */
848
+
849
+ readToken (token);
850
+
851
+ if (isType (token, TOKEN_OPEN_PAREN))
852
+ {
853
+ skipArgumentList(token);
854
+ }
855
+
856
+ if (isType (token, TOKEN_OPEN_CURLY))
857
+ {
858
+ do
859
+ {
860
+ readToken (token);
861
+ } while (! (isType (token, TOKEN_CLOSE_SGML) ||
862
+ isType (token, TOKEN_CLOSE_MXML) ||
863
+ isType (token, TOKEN_CLOSE_CURLY) ||
864
+ isType (token, TOKEN_GREATER_THAN)) );
865
+ }
866
+
867
+ }
868
+
869
+ static void parseLoop (tokenInfo *const token)
870
+ {
871
+ /*
872
+ * Handles these statements
873
+ * for (x=0; x<3; x++)
874
+ * document.write("This text is repeated three times<br>");
875
+ *
876
+ * for (x=0; x<3; x++)
877
+ * {
878
+ * document.write("This text is repeated three times<br>");
879
+ * }
880
+ *
881
+ * while (number<5){
882
+ * document.write(number+"<br>");
883
+ * number++;
884
+ * }
885
+ *
886
+ * do{
887
+ * document.write(number+"<br>");
888
+ * number++;
889
+ * }
890
+ * while (number<5);
891
+ */
892
+
893
+ if (isKeyword (token, KEYWORD_for) || isKeyword (token, KEYWORD_while))
894
+ {
895
+ readToken(token);
896
+
897
+ if (isType (token, TOKEN_OPEN_PAREN))
898
+ {
899
+ /*
900
+ * Handle nameless functions, these will only
901
+ * be considered methods.
902
+ */
903
+ skipArgumentList(token);
904
+ }
905
+
906
+ if (isType (token, TOKEN_OPEN_CURLY))
907
+ {
908
+ /*
909
+ * This will be either a function or a class.
910
+ * We can only determine this by checking the body
911
+ * of the function. If we find a "this." we know
912
+ * it is a class, otherwise it is a function.
913
+ */
914
+ parseBlock (token, token);
915
+ }
916
+ else
917
+ {
918
+ parseLine(token);
919
+ }
920
+ }
921
+ else if (isKeyword (token, KEYWORD_do))
922
+ {
923
+ readToken(token);
924
+
925
+ if (isType (token, TOKEN_OPEN_CURLY))
926
+ {
927
+ /*
928
+ * This will be either a function or a class.
929
+ * We can only determine this by checking the body
930
+ * of the function. If we find a "this." we know
931
+ * it is a class, otherwise it is a function.
932
+ */
933
+ parseBlock (token, token);
934
+ }
935
+ else
936
+ {
937
+ parseLine(token);
938
+ }
939
+
940
+ readToken(token);
941
+
942
+ if (isKeyword (token, KEYWORD_while))
943
+ {
944
+ readToken(token);
945
+
946
+ if (isType (token, TOKEN_OPEN_PAREN))
947
+ {
948
+ /*
949
+ * Handle nameless functions, these will only
950
+ * be considered methods.
951
+ */
952
+ skipArgumentList(token);
953
+ }
954
+ }
955
+ }
956
+ }
957
+
958
+ static boolean parseIf (tokenInfo *const token)
959
+ {
960
+ boolean read_next_token = TRUE;
961
+ /*
962
+ * If statements have two forms
963
+ * if ( ... )
964
+ * one line;
965
+ *
966
+ * if ( ... )
967
+ * statement;
968
+ * else
969
+ * statement
970
+ *
971
+ * if ( ... ) {
972
+ * multiple;
973
+ * statements;
974
+ * }
975
+ *
976
+ *
977
+ * if ( ... ) {
978
+ * return elem
979
+ * }
980
+ *
981
+ * This example if correctly written, but the
982
+ * else contains only 1 statement without a terminator
983
+ * since the function finishes with the closing brace.
984
+ *
985
+ * function a(flag){
986
+ * if(flag)
987
+ * test(1);
988
+ * else
989
+ * test(2)
990
+ * }
991
+ *
992
+ * TODO: Deal with statements that can optional end
993
+ * without a semi-colon. Currently this messes up
994
+ * the parsing of blocks.
995
+ * Need to somehow detect this has happened, and either
996
+ * backup a token, or skip reading the next token if
997
+ * that is possible from all code locations.
998
+ *
999
+ */
1000
+
1001
+ readToken (token);
1002
+
1003
+ if (isKeyword (token, KEYWORD_if))
1004
+ {
1005
+ /*
1006
+ * Check for an "else if" and consume the "if"
1007
+ */
1008
+ readToken (token);
1009
+ }
1010
+
1011
+ if (isType (token, TOKEN_OPEN_PAREN))
1012
+ {
1013
+ /*
1014
+ * Handle nameless functions, these will only
1015
+ * be considered methods.
1016
+ */
1017
+ skipArgumentList(token);
1018
+ }
1019
+
1020
+ if (isType (token, TOKEN_OPEN_CURLY))
1021
+ {
1022
+ /*
1023
+ * This will be either a function or a class.
1024
+ * We can only determine this by checking the body
1025
+ * of the function. If we find a "this." we know
1026
+ * it is a class, otherwise it is a function.
1027
+ */
1028
+ parseBlock (token, token);
1029
+ }
1030
+ else
1031
+ {
1032
+ findCmdTerm (token);
1033
+
1034
+ /*
1035
+ * The IF could be followed by an ELSE statement.
1036
+ * This too could have two formats, a curly braced
1037
+ * multiline section, or another single line.
1038
+ */
1039
+
1040
+ if (isType (token, TOKEN_CLOSE_CURLY))
1041
+ {
1042
+ /*
1043
+ * This statement did not have a line terminator.
1044
+ */
1045
+ read_next_token = FALSE;
1046
+ }
1047
+ else
1048
+ {
1049
+ readToken (token);
1050
+
1051
+ if (isType (token, TOKEN_CLOSE_CURLY))
1052
+ {
1053
+ /*
1054
+ * This statement did not have a line terminator.
1055
+ */
1056
+ read_next_token = FALSE;
1057
+ }
1058
+ else
1059
+ {
1060
+ if (isKeyword (token, KEYWORD_else))
1061
+ read_next_token = parseIf (token);
1062
+ }
1063
+ }
1064
+ }
1065
+ return read_next_token;
1066
+ }
1067
+
1068
+ static void parseFunction (tokenInfo *const token)
1069
+ {
1070
+ tokenInfo *const name = newToken ();
1071
+
1072
+ /*
1073
+ * This deals with these formats
1074
+ * private static function ioErrorHandler( event:IOErrorEvent ):void {
1075
+ */
1076
+
1077
+ if ( isKeyword(token, KEYWORD_function) )
1078
+ {
1079
+ readToken (token);
1080
+ }
1081
+
1082
+ copyToken (name, token);
1083
+ /* Add scope in case this is an INNER function
1084
+ addToScope(name, token->scope);
1085
+ */
1086
+
1087
+ DebugStatement (
1088
+ debugPrintf (DEBUG_PARSE
1089
+ , "\n parseFunction: token isClass:%d scope:%s name:%s\n"
1090
+ , token->isClass
1091
+ , vStringValue(token->scope)
1092
+ , vStringValue(token->string)
1093
+ );
1094
+ );
1095
+ DebugStatement (
1096
+ debugPrintf (DEBUG_PARSE
1097
+ , "\n parseFunction: name isClass:%d scope:%s name:%s\n"
1098
+ , name->isClass
1099
+ , vStringValue(name->scope)
1100
+ , vStringValue(name->string)
1101
+ );
1102
+ );
1103
+
1104
+ readToken (token);
1105
+
1106
+ if ( isType (token, TOKEN_OPEN_PAREN) )
1107
+ skipArgumentList(token);
1108
+
1109
+ if ( isType (token, TOKEN_COLON) )
1110
+ {
1111
+ /*
1112
+ * function fname ():ReturnType
1113
+ */
1114
+ readToken (token);
1115
+ readToken (token);
1116
+ }
1117
+
1118
+ if ( isType (token, TOKEN_OPEN_CURLY) )
1119
+ {
1120
+ DebugStatement (
1121
+ debugPrintf (DEBUG_PARSE
1122
+ , "\n parseFunction end: name isClass:%d scope:%s name:%s\n"
1123
+ , name->isClass
1124
+ , vStringValue(name->scope)
1125
+ , vStringValue(name->string)
1126
+ );
1127
+ );
1128
+ parseBlock (token, name);
1129
+ DebugStatement (
1130
+ debugPrintf (DEBUG_PARSE
1131
+ , "\n parseFunction end2: token isClass:%d scope:%s name:%s\n"
1132
+ , token->isClass
1133
+ , vStringValue(token->scope)
1134
+ , vStringValue(token->string)
1135
+ );
1136
+ );
1137
+ DebugStatement (
1138
+ debugPrintf (DEBUG_PARSE
1139
+ , "\n parseFunction end2: token isClass:%d scope:%s name:%s\n"
1140
+ , token->isClass
1141
+ , vStringValue(token->scope)
1142
+ , vStringValue(token->string)
1143
+ );
1144
+ );
1145
+ DebugStatement (
1146
+ debugPrintf (DEBUG_PARSE
1147
+ , "\n parseFunction end3: name isClass:%d scope:%s name:%s\n"
1148
+ , name->isClass
1149
+ , vStringValue(name->scope)
1150
+ , vStringValue(name->string)
1151
+ );
1152
+ );
1153
+ makeFunctionTag (name);
1154
+ }
1155
+
1156
+ findCmdTerm (token);
1157
+
1158
+ deleteToken (name);
1159
+ }
1160
+
1161
+ static boolean parseBlock (tokenInfo *const token, tokenInfo *const parent)
1162
+ {
1163
+ boolean read_next_token = TRUE;
1164
+ vString * saveScope = vStringNew ();
1165
+
1166
+ vStringClear(saveScope);
1167
+ vStringCopy (saveScope, token->scope);
1168
+ token->nestLevel++;
1169
+ DebugStatement (
1170
+ debugPrintf (DEBUG_PARSE
1171
+ , "\n parseBlock start: token isClass:%d scope:%s name:%s\n"
1172
+ , token->isClass
1173
+ , vStringValue(token->scope)
1174
+ , vStringValue(token->string)
1175
+ );
1176
+ );
1177
+ /*
1178
+ * Make this routine a bit more forgiving.
1179
+ * If called on an open_curly advance it
1180
+ */
1181
+ if ( isType (token, TOKEN_OPEN_CURLY) &&
1182
+ isKeyword(token, KEYWORD_NONE) )
1183
+ readToken(token);
1184
+
1185
+ if (! isType (token, TOKEN_CLOSE_CURLY))
1186
+ {
1187
+ /*
1188
+ * Read until we find the closing brace,
1189
+ * any nested braces will be handled within
1190
+ */
1191
+ do
1192
+ {
1193
+ if (isType (token, TOKEN_OPEN_CURLY))
1194
+ {
1195
+ /* Handle nested blocks */
1196
+ parseBlock (token, parent);
1197
+ }
1198
+ else
1199
+ {
1200
+ /*
1201
+ * It is possible for a line to have no terminator
1202
+ * if the following line is a closing brace.
1203
+ * parseLine will detect this case and indicate
1204
+ * whether we should read an additional token.
1205
+ */
1206
+ read_next_token = parseLine (token);
1207
+ }
1208
+
1209
+ /*
1210
+ * Always read a new token unless we find a statement without
1211
+ * a ending terminator
1212
+ */
1213
+ if( read_next_token )
1214
+ readToken(token);
1215
+
1216
+ /*
1217
+ * If we find a statement without a terminator consider the
1218
+ * block finished, otherwise the stack will be off by one.
1219
+ */
1220
+ } while (! isType (token, TOKEN_CLOSE_CURLY) && read_next_token );
1221
+ }
1222
+
1223
+ vStringDelete(saveScope);
1224
+ token->nestLevel--;
1225
+
1226
+ DebugStatement (
1227
+ debugPrintf (DEBUG_PARSE
1228
+ , "\n parseBlock end: token isClass:%d scope:%s name:%s\n"
1229
+ , token->isClass
1230
+ , vStringValue(token->scope)
1231
+ , vStringValue(token->string)
1232
+ );
1233
+ );
1234
+ return FALSE;
1235
+ }
1236
+
1237
+ static void parseMethods (tokenInfo *const token, tokenInfo *const class)
1238
+ {
1239
+ tokenInfo *const name = newToken ();
1240
+
1241
+ /*
1242
+ * This deals with these formats
1243
+ * validProperty : 2,
1244
+ * validMethod : function(a,b) {}
1245
+ * 'validMethod2' : function(a,b) {}
1246
+ * container.dirtyTab = {'url': false, 'title':false, 'snapshot':false, '*': false}
1247
+ */
1248
+
1249
+ do
1250
+ {
1251
+ readToken (token);
1252
+ if (isType (token, TOKEN_STRING) || isKeyword(token, KEYWORD_NONE))
1253
+ {
1254
+ copyToken (name, token);
1255
+
1256
+ readToken (token);
1257
+ if ( isType (token, TOKEN_COLON) )
1258
+ {
1259
+ readToken (token);
1260
+ if ( isKeyword (token, KEYWORD_function) )
1261
+ {
1262
+ readToken (token);
1263
+ if ( isType (token, TOKEN_OPEN_PAREN) )
1264
+ {
1265
+ skipArgumentList(token);
1266
+ }
1267
+
1268
+ if (isType (token, TOKEN_OPEN_CURLY))
1269
+ {
1270
+ addToScope (name, class->string);
1271
+ makeFlexTag (name, FLEXTAG_METHOD);
1272
+ parseBlock (token, name);
1273
+
1274
+ /*
1275
+ * Read to the closing curly, check next
1276
+ * token, if a comma, we must loop again
1277
+ */
1278
+ readToken (token);
1279
+ }
1280
+ }
1281
+ else
1282
+ {
1283
+ addToScope (name, class->string);
1284
+ makeFlexTag (name, FLEXTAG_PROPERTY);
1285
+
1286
+ /*
1287
+ * Read the next token, if a comma
1288
+ * we must loop again
1289
+ */
1290
+ readToken (token);
1291
+ }
1292
+ }
1293
+ }
1294
+ } while ( isType(token, TOKEN_COMMA) );
1295
+
1296
+ findCmdTerm (token);
1297
+
1298
+ deleteToken (name);
1299
+ }
1300
+
1301
+ static boolean parseVar (tokenInfo *const token, boolean is_public)
1302
+ {
1303
+ tokenInfo *const name = newToken ();
1304
+ tokenInfo *const secondary_name = newToken ();
1305
+ vString * saveScope = vStringNew ();
1306
+ boolean is_terminated = TRUE;
1307
+
1308
+ vStringClear(saveScope);
1309
+ vStringCopy (saveScope, token->scope);
1310
+ /*
1311
+ * Variables are defined as:
1312
+ * private static var lastFaultMessage:Date = new Date( 0 );
1313
+ * private static var webRequests:ArrayCollection = new ArrayCollection();
1314
+ */
1315
+
1316
+ if ( isKeyword(token, KEYWORD_var) )
1317
+ {
1318
+ readToken(token);
1319
+ }
1320
+
1321
+ /* Variable name */
1322
+ copyToken (name, token);
1323
+ readToken(token);
1324
+
1325
+ if ( isType (token, TOKEN_COLON) )
1326
+ {
1327
+ /*
1328
+ * var vname ():DataType = new Date();
1329
+ * var vname ():DataType;
1330
+ */
1331
+ readToken (token);
1332
+ readToken (token);
1333
+ }
1334
+
1335
+ while (! isType (token, TOKEN_SEMICOLON) )
1336
+ {
1337
+ readToken (token);
1338
+ }
1339
+
1340
+ if ( isType (token, TOKEN_SEMICOLON) )
1341
+ {
1342
+ /*
1343
+ * Only create variables for global scope
1344
+ */
1345
+ /* if ( token->nestLevel == 0 && is_global ) */
1346
+ if ( is_public )
1347
+ {
1348
+ if (isType (token, TOKEN_SEMICOLON))
1349
+ makeFlexTag (name, FLEXTAG_VARIABLE);
1350
+ }
1351
+ }
1352
+
1353
+ vStringCopy(token->scope, saveScope);
1354
+ deleteToken (name);
1355
+ deleteToken (secondary_name);
1356
+ vStringDelete(saveScope);
1357
+
1358
+ return is_terminated;
1359
+ }
1360
+
1361
+ static boolean parseClass (tokenInfo *const token)
1362
+ {
1363
+ tokenInfo *const name = newToken ();
1364
+ vString * saveScope = vStringNew ();
1365
+ boolean saveIsClass = token->isClass;
1366
+
1367
+ vStringClear(saveScope);
1368
+ vStringCopy (saveScope, token->scope);
1369
+ /*
1370
+ * Variables are defined as:
1371
+ * private static var lastFaultMessage:Date = new Date( 0 );
1372
+ * private static var webRequests:ArrayCollection = new ArrayCollection();
1373
+ */
1374
+
1375
+ if ( isKeyword(token, KEYWORD_class) )
1376
+ {
1377
+ readToken(token);
1378
+ }
1379
+
1380
+ token->isClass = TRUE;
1381
+ /* Add class name to scope */
1382
+ addToScope(token, token->string);
1383
+ /* Class name */
1384
+ copyToken (name, token);
1385
+ readToken(token);
1386
+
1387
+ DebugStatement (
1388
+ debugPrintf (DEBUG_PARSE
1389
+ , "\n parseClass start: token isClass:%d scope:%s name:%s\n"
1390
+ , token->isClass
1391
+ , vStringValue(token->scope)
1392
+ , vStringValue(token->string)
1393
+ );
1394
+ );
1395
+ if ( isType (token, TOKEN_OPEN_CURLY) )
1396
+ {
1397
+ makeClassTag (name);
1398
+ parseBlock (token, name);
1399
+ }
1400
+
1401
+ DebugStatement (
1402
+ debugPrintf (DEBUG_PARSE
1403
+ , "\n parseClass end: token isClass:%d scope:%s name:%s\n"
1404
+ , token->isClass
1405
+ , vStringValue(token->scope)
1406
+ , vStringValue(token->string)
1407
+ );
1408
+ );
1409
+ vStringCopy(token->scope, saveScope);
1410
+ token->isClass = saveIsClass;
1411
+ deleteToken (name);
1412
+ vStringDelete(saveScope);
1413
+
1414
+ return TRUE;
1415
+ }
1416
+
1417
+ static boolean parseStatement (tokenInfo *const token)
1418
+ {
1419
+ tokenInfo *const name = newToken ();
1420
+ tokenInfo *const secondary_name = newToken ();
1421
+ vString * saveScope = vStringNew ();
1422
+ boolean is_public = FALSE;
1423
+ boolean is_class = FALSE;
1424
+ boolean is_terminated = TRUE;
1425
+ boolean is_global = FALSE;
1426
+ boolean is_prototype = FALSE;
1427
+ vString * fulltag;
1428
+
1429
+ vStringClear(saveScope);
1430
+ vStringCopy (saveScope, token->scope);
1431
+ DebugStatement (
1432
+ debugPrintf (DEBUG_PARSE
1433
+ , "\n parseStatement: token isClass:%d scope:%s name:%s\n"
1434
+ , token->isClass
1435
+ , vStringValue(token->scope)
1436
+ , vStringValue(token->string)
1437
+ );
1438
+ );
1439
+ /*
1440
+ * Functions can be named or unnamed.
1441
+ * This deals with these formats:
1442
+ * Function
1443
+ * validFunctionOne = function(a,b) {}
1444
+ * testlib.validFunctionFive = function(a,b) {}
1445
+ * var innerThree = function(a,b) {}
1446
+ * var innerFour = (a,b) {}
1447
+ * var D2 = secondary_fcn_name(a,b) {}
1448
+ * var D3 = new Function("a", "b", "return a+b;");
1449
+ * Class
1450
+ * testlib.extras.ValidClassOne = function(a,b) {
1451
+ * this.a = a;
1452
+ * }
1453
+ * Class Methods
1454
+ * testlib.extras.ValidClassOne.prototype = {
1455
+ * 'validMethodOne' : function(a,b) {},
1456
+ * 'validMethodTwo' : function(a,b) {}
1457
+ * }
1458
+ * ValidClassTwo = function ()
1459
+ * {
1460
+ * this.validMethodThree = function() {}
1461
+ * // unnamed method
1462
+ * this.validMethodFour = () {}
1463
+ * }
1464
+ * Database.prototype.validMethodThree = Database_getTodaysDate;
1465
+ */
1466
+
1467
+ if ( isKeyword(token, KEYWORD_public) )
1468
+ {
1469
+ is_public = TRUE;
1470
+ readToken(token);
1471
+ }
1472
+
1473
+ if ( isKeyword(token, KEYWORD_private) )
1474
+ {
1475
+ readToken(token);
1476
+ }
1477
+
1478
+ if ( isKeyword(token, KEYWORD_static) )
1479
+ {
1480
+ readToken(token);
1481
+ }
1482
+
1483
+ if (isType(token, TOKEN_KEYWORD))
1484
+ {
1485
+ switch (token->keyword)
1486
+ {
1487
+ case KEYWORD_for:
1488
+ case KEYWORD_while:
1489
+ case KEYWORD_do:
1490
+ parseLoop (token);
1491
+ break;
1492
+ case KEYWORD_if:
1493
+ case KEYWORD_else:
1494
+ case KEYWORD_try:
1495
+ case KEYWORD_catch:
1496
+ case KEYWORD_finally:
1497
+ /* Common semantics */
1498
+ is_terminated = parseIf (token);
1499
+ break;
1500
+ case KEYWORD_switch:
1501
+ parseSwitch (token);
1502
+ break;
1503
+ case KEYWORD_class:
1504
+ parseClass (token);
1505
+ return is_terminated;
1506
+ break;
1507
+ case KEYWORD_function:
1508
+ parseFunction (token);
1509
+ return is_terminated;
1510
+ break;
1511
+ case KEYWORD_var:
1512
+ parseVar (token, is_public);
1513
+ return is_terminated;
1514
+ break;
1515
+ default:
1516
+ readToken(token);
1517
+ break;
1518
+ }
1519
+ }
1520
+
1521
+ copyToken (name, token);
1522
+
1523
+ while (! isType (token, TOKEN_CLOSE_CURLY) &&
1524
+ ! isType (token, TOKEN_SEMICOLON) &&
1525
+ ! isType (token, TOKEN_EQUAL_SIGN) )
1526
+ {
1527
+ /* Potentially the name of the function */
1528
+ readToken (token);
1529
+ if (isType (token, TOKEN_PERIOD))
1530
+ {
1531
+ /*
1532
+ * Cannot be a global variable is it has dot references in the name
1533
+ */
1534
+ is_global = FALSE;
1535
+ do
1536
+ {
1537
+ readToken (token);
1538
+ if ( isKeyword(token, KEYWORD_NONE) )
1539
+ {
1540
+ if ( is_class )
1541
+ {
1542
+ vStringCopy(saveScope, token->scope);
1543
+ addToScope(token, name->string);
1544
+ }
1545
+ else
1546
+ addContext (name, token);
1547
+ }
1548
+ else if ( isKeyword(token, KEYWORD_prototype) )
1549
+ {
1550
+ /*
1551
+ * When we reach the "prototype" tag, we infer:
1552
+ * "BindAgent" is a class
1553
+ * "build" is a method
1554
+ *
1555
+ * function BindAgent( repeatableIdName, newParentIdName ) {
1556
+ * }
1557
+ *
1558
+ * CASE 1
1559
+ * Specified function name: "build"
1560
+ * BindAgent.prototype.build = function( mode ) {
1561
+ * ignore everything within this function
1562
+ * }
1563
+ *
1564
+ * CASE 2
1565
+ * Prototype listing
1566
+ * ValidClassOne.prototype = {
1567
+ * 'validMethodOne' : function(a,b) {},
1568
+ * 'validMethodTwo' : function(a,b) {}
1569
+ * }
1570
+ *
1571
+ */
1572
+ makeClassTag (name);
1573
+ is_class = TRUE;
1574
+ is_prototype = TRUE;
1575
+
1576
+ /*
1577
+ * There should a ".function_name" next.
1578
+ */
1579
+ readToken (token);
1580
+ if (isType (token, TOKEN_PERIOD))
1581
+ {
1582
+ /*
1583
+ * Handle CASE 1
1584
+ */
1585
+ readToken (token);
1586
+ if ( isKeyword(token, KEYWORD_NONE) )
1587
+ {
1588
+ vStringCopy(saveScope, token->scope);
1589
+ addToScope(token, name->string);
1590
+
1591
+ makeFlexTag (token, FLEXTAG_METHOD);
1592
+ /*
1593
+ * We can read until the end of the block / statement.
1594
+ * We need to correctly parse any nested blocks, but
1595
+ * we do NOT want to create any tags based on what is
1596
+ * within the blocks.
1597
+ */
1598
+ token->ignoreTag = TRUE;
1599
+ /*
1600
+ * Find to the end of the statement
1601
+ */
1602
+ findCmdTerm (token);
1603
+ token->ignoreTag = FALSE;
1604
+ is_terminated = TRUE;
1605
+ goto cleanUp;
1606
+ }
1607
+ }
1608
+ else if (isType (token, TOKEN_EQUAL_SIGN))
1609
+ {
1610
+ readToken (token);
1611
+ if (isType (token, TOKEN_OPEN_CURLY))
1612
+ {
1613
+ /*
1614
+ * Handle CASE 2
1615
+ *
1616
+ * Creates tags for each of these class methods
1617
+ * ValidClassOne.prototype = {
1618
+ * 'validMethodOne' : function(a,b) {},
1619
+ * 'validMethodTwo' : function(a,b) {}
1620
+ * }
1621
+ */
1622
+ parseMethods(token, name);
1623
+ /*
1624
+ * Find to the end of the statement
1625
+ */
1626
+ findCmdTerm (token);
1627
+ token->ignoreTag = FALSE;
1628
+ is_terminated = TRUE;
1629
+ goto cleanUp;
1630
+ }
1631
+ }
1632
+ }
1633
+ readToken (token);
1634
+ } while (isType (token, TOKEN_PERIOD));
1635
+ }
1636
+
1637
+ if ( isType (token, TOKEN_OPEN_PAREN) )
1638
+ skipArgumentList(token);
1639
+
1640
+ if ( isType (token, TOKEN_COLON) )
1641
+ {
1642
+ /*
1643
+ * Functions are of this form:
1644
+ * function fname ():ReturnType {
1645
+ */
1646
+ readToken (token);
1647
+ readToken (token);
1648
+ }
1649
+
1650
+ if ( isType (token, TOKEN_OPEN_SQUARE) )
1651
+ skipArrayList(token);
1652
+
1653
+ }
1654
+
1655
+ if ( isType (token, TOKEN_CLOSE_CURLY) )
1656
+ {
1657
+ /*
1658
+ * Reaching this section without having
1659
+ * processed an open curly brace indicates
1660
+ * the statement is most likely not terminated.
1661
+ */
1662
+ is_terminated = FALSE;
1663
+ goto cleanUp;
1664
+ }
1665
+
1666
+ if ( isType (token, TOKEN_SEMICOLON) )
1667
+ {
1668
+ /*
1669
+ * Only create variables for global scope
1670
+ */
1671
+ if ( token->nestLevel == 0 && is_global )
1672
+ {
1673
+ /*
1674
+ * Handles this syntax:
1675
+ * var g_var2;
1676
+ */
1677
+ if (isType (token, TOKEN_SEMICOLON))
1678
+ makeFlexTag (name, FLEXTAG_VARIABLE);
1679
+ }
1680
+ /*
1681
+ * Statement has ended.
1682
+ * This deals with calls to functions, like:
1683
+ * alert(..);
1684
+ */
1685
+ goto cleanUp;
1686
+ }
1687
+
1688
+ if ( isType (token, TOKEN_EQUAL_SIGN) )
1689
+ {
1690
+ readToken (token);
1691
+
1692
+ if ( isKeyword (token, KEYWORD_function) )
1693
+ {
1694
+ readToken (token);
1695
+
1696
+ if ( isKeyword (token, KEYWORD_NONE) &&
1697
+ ! isType (token, TOKEN_OPEN_PAREN) )
1698
+ {
1699
+ /*
1700
+ * Functions of this format:
1701
+ * var D2A = function theAdd(a, b)
1702
+ * {
1703
+ * return a+b;
1704
+ * }
1705
+ * Are really two separate defined functions and
1706
+ * can be referenced in two ways:
1707
+ * alert( D2A(1,2) ); // produces 3
1708
+ * alert( theAdd(1,2) ); // also produces 3
1709
+ * So it must have two tags:
1710
+ * D2A
1711
+ * theAdd
1712
+ * Save the reference to the name for later use, once
1713
+ * we have established this is a valid function we will
1714
+ * create the secondary reference to it.
1715
+ */
1716
+ copyToken (secondary_name, token);
1717
+ readToken (token);
1718
+ }
1719
+
1720
+ if ( isType (token, TOKEN_OPEN_PAREN) )
1721
+ skipArgumentList(token);
1722
+
1723
+ if (isType (token, TOKEN_OPEN_CURLY))
1724
+ {
1725
+ /*
1726
+ * This will be either a function or a class.
1727
+ * We can only determine this by checking the body
1728
+ * of the function. If we find a "this." we know
1729
+ * it is a class, otherwise it is a function.
1730
+ */
1731
+ if ( token->isClass )
1732
+ {
1733
+ makeFlexTag (name, FLEXTAG_METHOD);
1734
+ if ( vStringLength(secondary_name->string) > 0 )
1735
+ makeFunctionTag (secondary_name);
1736
+ parseBlock (token, name);
1737
+ }
1738
+ else
1739
+ {
1740
+ parseBlock (token, name);
1741
+ makeFunctionTag (name);
1742
+
1743
+ if ( vStringLength(secondary_name->string) > 0 )
1744
+ makeFunctionTag (secondary_name);
1745
+
1746
+ /*
1747
+ * Find to the end of the statement
1748
+ */
1749
+ goto cleanUp;
1750
+ }
1751
+ }
1752
+ }
1753
+ else if (isType (token, TOKEN_OPEN_PAREN))
1754
+ {
1755
+ /*
1756
+ * Handle nameless functions
1757
+ * this.method_name = () {}
1758
+ */
1759
+ skipArgumentList(token);
1760
+
1761
+ if (isType (token, TOKEN_OPEN_CURLY))
1762
+ {
1763
+ /*
1764
+ * Nameless functions are only setup as methods.
1765
+ */
1766
+ makeFlexTag (name, FLEXTAG_METHOD);
1767
+ parseBlock (token, name);
1768
+ }
1769
+ }
1770
+ else if (isType (token, TOKEN_OPEN_CURLY))
1771
+ {
1772
+ /*
1773
+ * Creates tags for each of these class methods
1774
+ * ValidClassOne.prototype = {
1775
+ * 'validMethodOne' : function(a,b) {},
1776
+ * 'validMethodTwo' : function(a,b) {}
1777
+ * }
1778
+ */
1779
+ parseMethods(token, name);
1780
+ if (isType (token, TOKEN_CLOSE_CURLY))
1781
+ {
1782
+ /*
1783
+ * Assume the closing parantheses terminates
1784
+ * this statements.
1785
+ */
1786
+ is_terminated = TRUE;
1787
+ }
1788
+ }
1789
+ else if (isKeyword (token, KEYWORD_new))
1790
+ {
1791
+ readToken (token);
1792
+ if ( isKeyword (token, KEYWORD_function) ||
1793
+ isKeyword (token, KEYWORD_capital_function) ||
1794
+ isKeyword (token, KEYWORD_object) ||
1795
+ isKeyword (token, KEYWORD_capital_object) )
1796
+ {
1797
+ if ( isKeyword (token, KEYWORD_object) ||
1798
+ isKeyword (token, KEYWORD_capital_object) )
1799
+ is_class = TRUE;
1800
+
1801
+ readToken (token);
1802
+ if ( isType (token, TOKEN_OPEN_PAREN) )
1803
+ skipArgumentList(token);
1804
+
1805
+ if (isType (token, TOKEN_SEMICOLON))
1806
+ {
1807
+ if ( token->nestLevel == 0 )
1808
+ {
1809
+ if ( is_class )
1810
+ {
1811
+ makeClassTag (name);
1812
+ } else {
1813
+ makeFunctionTag (name);
1814
+ }
1815
+ }
1816
+ }
1817
+ }
1818
+ }
1819
+ else if (isKeyword (token, KEYWORD_NONE))
1820
+ {
1821
+ /*
1822
+ * Only create variables for global scope
1823
+ */
1824
+ if ( token->nestLevel == 0 && is_global )
1825
+ {
1826
+ /*
1827
+ * A pointer can be created to the function.
1828
+ * If we recognize the function/class name ignore the variable.
1829
+ * This format looks identical to a variable definition.
1830
+ * A variable defined outside of a block is considered
1831
+ * a global variable:
1832
+ * var g_var1 = 1;
1833
+ * var g_var2;
1834
+ * This is not a global variable:
1835
+ * var g_var = function;
1836
+ * This is a global variable:
1837
+ * var g_var = different_var_name;
1838
+ */
1839
+ fulltag = vStringNew ();
1840
+ if (vStringLength (token->scope) > 0)
1841
+ {
1842
+ vStringCopy(fulltag, token->scope);
1843
+ vStringCatS (fulltag, ".");
1844
+ vStringCatS (fulltag, vStringValue(token->string));
1845
+ }
1846
+ else
1847
+ {
1848
+ vStringCopy(fulltag, token->string);
1849
+ }
1850
+ vStringTerminate(fulltag);
1851
+ if ( ! stringListHas(FunctionNames, vStringValue (fulltag)) &&
1852
+ ! stringListHas(ClassNames, vStringValue (fulltag)) )
1853
+ {
1854
+ findCmdTerm (token);
1855
+ if (isType (token, TOKEN_SEMICOLON))
1856
+ makeFlexTag (name, FLEXTAG_VARIABLE);
1857
+ }
1858
+ vStringDelete (fulltag);
1859
+ }
1860
+ }
1861
+ }
1862
+ findCmdTerm (token);
1863
+
1864
+ /*
1865
+ * Statements can be optionally terminated in the case of
1866
+ * statement prior to a close curly brace as in the
1867
+ * document.write line below:
1868
+ *
1869
+ * function checkForUpdate() {
1870
+ * if( 1==1 ) {
1871
+ * document.write("hello from checkForUpdate<br>")
1872
+ * }
1873
+ * return 1;
1874
+ * }
1875
+ */
1876
+ if ( ! is_terminated && isType (token, TOKEN_CLOSE_CURLY))
1877
+ is_terminated = FALSE;
1878
+
1879
+
1880
+ cleanUp:
1881
+ vStringCopy(token->scope, saveScope);
1882
+ deleteToken (name);
1883
+ deleteToken (secondary_name);
1884
+ vStringDelete(saveScope);
1885
+
1886
+ return is_terminated;
1887
+ }
1888
+
1889
+ static boolean parseLine (tokenInfo *const token)
1890
+ {
1891
+ boolean is_terminated = TRUE;
1892
+ /*
1893
+ * Detect the common statements, if, while, for, do, ...
1894
+ * This is necessary since the last statement within a block "{}"
1895
+ * can be optionally terminated.
1896
+ *
1897
+ * If the statement is not terminated, we need to tell
1898
+ * the calling routine to prevent reading an additional token
1899
+ * looking for the end of the statement.
1900
+ */
1901
+
1902
+ if (isType(token, TOKEN_KEYWORD))
1903
+ {
1904
+ switch (token->keyword)
1905
+ {
1906
+ case KEYWORD_for:
1907
+ case KEYWORD_while:
1908
+ case KEYWORD_do:
1909
+ parseLoop (token);
1910
+ break;
1911
+ case KEYWORD_if:
1912
+ case KEYWORD_else:
1913
+ case KEYWORD_try:
1914
+ case KEYWORD_catch:
1915
+ case KEYWORD_finally:
1916
+ /* Common semantics */
1917
+ is_terminated = parseIf (token);
1918
+ break;
1919
+ case KEYWORD_switch:
1920
+ parseSwitch (token);
1921
+ break;
1922
+ default:
1923
+ parseStatement (token);
1924
+ break;
1925
+ }
1926
+ }
1927
+ else
1928
+ {
1929
+ /*
1930
+ * Special case where single line statements may not be
1931
+ * SEMICOLON terminated. parseBlock needs to know this
1932
+ * so that it does not read the next token.
1933
+ */
1934
+ is_terminated = parseStatement (token);
1935
+ }
1936
+ return is_terminated;
1937
+ }
1938
+
1939
+ static boolean parseCDATA (tokenInfo *const token)
1940
+ {
1941
+ if (isType (token, TOKEN_LESS_THAN))
1942
+ {
1943
+ /*
1944
+ * Handle these tags
1945
+ * <![CDATA[
1946
+ * ...
1947
+ * ]]>
1948
+ */
1949
+ readToken (token);
1950
+ if (isType (token, TOKEN_EXCLAMATION))
1951
+ {
1952
+ /*
1953
+ * Not sure why I had to comment these out, but I did.
1954
+ * readToken (token);
1955
+ * if (isType (token, TOKEN_OPEN_SQUARE))
1956
+ * {
1957
+ */
1958
+ readToken (token);
1959
+ if (isKeyword (token, KEYWORD_cdata))
1960
+ {
1961
+ readToken (token);
1962
+ if (isType (token, TOKEN_OPEN_SQUARE))
1963
+ {
1964
+ parseActionScript (token);
1965
+ if (isType (token, TOKEN_CLOSE_SQUARE))
1966
+ {
1967
+ readToken (token);
1968
+ if (isType (token, TOKEN_CLOSE_SQUARE))
1969
+ {
1970
+ readToken (token);
1971
+ }
1972
+ }
1973
+ }
1974
+ }
1975
+ /*} Not sure */
1976
+ }
1977
+ }
1978
+ else
1979
+ {
1980
+ parseActionScript (token);
1981
+ }
1982
+ return TRUE;
1983
+ }
1984
+
1985
+ static boolean parseMXML (tokenInfo *const token)
1986
+ {
1987
+ tokenInfo *const name = newToken ();
1988
+ tokenInfo *const type = newToken ();
1989
+ /*
1990
+ * Detect the common statements, if, while, for, do, ...
1991
+ * This is necessary since the last statement within a block "{}"
1992
+ * can be optionally terminated.
1993
+ *
1994
+ * If the statement is not terminated, we need to tell
1995
+ * the calling routine to prevent reading an additional token
1996
+ * looking for the end of the statement.
1997
+ */
1998
+
1999
+ readToken (token);
2000
+
2001
+ if (isKeyword (token, KEYWORD_script))
2002
+ {
2003
+ /*
2004
+ * These tags can be of this form:
2005
+ * <mx:Script src="filename.as" />
2006
+ */
2007
+ do
2008
+ {
2009
+ readToken (token);
2010
+ } while (! (isType (token, TOKEN_CLOSE_SGML) ||
2011
+ isType (token, TOKEN_CLOSE_MXML) ||
2012
+ isType (token, TOKEN_GREATER_THAN)) );
2013
+
2014
+ if (isType (token, TOKEN_CLOSE_MXML))
2015
+ {
2016
+ /*
2017
+ * We have found a </mx:type> tag
2018
+ * Finish reading the "type" and ">"
2019
+ */
2020
+ readToken (token);
2021
+ readToken (token);
2022
+ goto cleanUp;
2023
+ }
2024
+ if (isType (token, TOKEN_CLOSE_SGML))
2025
+ {
2026
+ /*
2027
+ * We have found a <mx:Script src="filename.as" />
2028
+ */
2029
+ goto cleanUp;
2030
+ }
2031
+
2032
+ /*
2033
+ * This is a beginning of an embedded script.
2034
+ * These typically are of this format:
2035
+ * <mx:Script>
2036
+ * <![CDATA[
2037
+ * ... ActionScript ...
2038
+ * ]]>
2039
+ * </mx:Script>
2040
+ */
2041
+ readToken (token);
2042
+ parseCDATA (token);
2043
+
2044
+ readToken (token);
2045
+ if (isType (token, TOKEN_CLOSE_MXML))
2046
+ {
2047
+ /*
2048
+ * We have found a </mx:type> tag
2049
+ * Finish reading the "type" and ">"
2050
+ */
2051
+ readToken (token);
2052
+ readToken (token);
2053
+ }
2054
+ goto cleanUp;
2055
+ }
2056
+
2057
+ copyToken (type, token);
2058
+
2059
+ readToken (token);
2060
+ do
2061
+ {
2062
+ if (isType (token, TOKEN_OPEN_MXML))
2063
+ {
2064
+ parseMXML (token);
2065
+ }
2066
+ else if (isKeyword (token, KEYWORD_id))
2067
+ {
2068
+ /* = */
2069
+ readToken (token);
2070
+ readToken (token);
2071
+
2072
+ copyToken (name, token);
2073
+ addToScope (name, type->string);
2074
+ makeMXTag (name);
2075
+ }
2076
+ readToken (token);
2077
+ } while (! (isType (token, TOKEN_CLOSE_SGML) || isType (token, TOKEN_CLOSE_MXML)) );
2078
+
2079
+ if (isType (token, TOKEN_CLOSE_MXML))
2080
+ {
2081
+ /*
2082
+ * We have found a </mx:type> tag
2083
+ * Finish reading the "type" and ">"
2084
+ */
2085
+ readToken (token);
2086
+ readToken (token);
2087
+ }
2088
+
2089
+ cleanUp:
2090
+ deleteToken (name);
2091
+ deleteToken (type);
2092
+ return TRUE;
2093
+ }
2094
+
2095
+ static boolean parseActionScript (tokenInfo *const token)
2096
+ {
2097
+ do
2098
+ {
2099
+ readToken (token);
2100
+
2101
+ if (isType (token, TOKEN_LESS_THAN))
2102
+ {
2103
+ /*
2104
+ * Handle these tags
2105
+ * <![CDATA[
2106
+ * ...
2107
+ * ]]>
2108
+ */
2109
+ readToken (token);
2110
+ if (isType (token, TOKEN_EQUAL_SIGN))
2111
+ {
2112
+ if (isType (token, TOKEN_OPEN_SQUARE))
2113
+ {
2114
+ readToken (token);
2115
+ if (isKeyword (token, KEYWORD_cdata))
2116
+ {
2117
+ readToken (token);
2118
+ }
2119
+ }
2120
+ }
2121
+ }
2122
+ if (isType (token, TOKEN_CLOSE_SQUARE))
2123
+ {
2124
+ /*
2125
+ * Handle these tags
2126
+ * <![CDATA[
2127
+ * ...
2128
+ * ]]>
2129
+ */
2130
+ readToken (token);
2131
+ if (isType (token, TOKEN_CLOSE_SQUARE))
2132
+ {
2133
+ readToken (token);
2134
+ if (isType (token, TOKEN_GREATER_THAN))
2135
+ {
2136
+ return TRUE;
2137
+ }
2138
+ }
2139
+ }
2140
+ else if (isType (token, TOKEN_CLOSE_MXML))
2141
+ {
2142
+ /*
2143
+ * Read the Script> tags
2144
+ */
2145
+ readToken (token);
2146
+ readToken (token);
2147
+ return TRUE;
2148
+ }
2149
+ else if (isType (token, TOKEN_OPEN_MXML))
2150
+ {
2151
+ parseMXML (token);
2152
+ }
2153
+ else
2154
+ {
2155
+ if (isType(token, TOKEN_KEYWORD))
2156
+ {
2157
+ switch (token->keyword)
2158
+ {
2159
+ case KEYWORD_function: parseFunction (token); break;
2160
+ default: parseLine (token); break;
2161
+ }
2162
+ }
2163
+ else
2164
+ {
2165
+ parseLine (token);
2166
+ }
2167
+ }
2168
+ } while (TRUE);
2169
+ }
2170
+
2171
+ static void parseFlexFile (tokenInfo *const token)
2172
+ {
2173
+ do
2174
+ {
2175
+ readToken (token);
2176
+
2177
+ if (isType (token, TOKEN_OPEN_MXML))
2178
+ {
2179
+ parseMXML (token);
2180
+ }
2181
+ if (isType (token, TOKEN_LESS_THAN))
2182
+ {
2183
+ readToken (token);
2184
+ if (isType (token, TOKEN_QUESTION_MARK))
2185
+ {
2186
+ readToken (token);
2187
+ while (! isType (token, TOKEN_QUESTION_MARK) )
2188
+ {
2189
+ readToken (token);
2190
+ }
2191
+ readToken (token);
2192
+ }
2193
+ }
2194
+ else
2195
+ {
2196
+ parseActionScript (token);
2197
+ }
2198
+ } while (TRUE);
2199
+ }
2200
+
2201
+ static void initialize (const langType language)
2202
+ {
2203
+ Assert (sizeof (FlexKinds) / sizeof (FlexKinds [0]) == FLEXTAG_COUNT);
2204
+ Lang_js = language;
2205
+ buildFlexKeywordHash ();
2206
+ }
2207
+
2208
+ static void findFlexTags (void)
2209
+ {
2210
+ tokenInfo *const token = newToken ();
2211
+ exception_t exception;
2212
+
2213
+ ClassNames = stringListNew ();
2214
+ FunctionNames = stringListNew ();
2215
+
2216
+ exception = (exception_t) (setjmp (Exception));
2217
+ while (exception == ExceptionNone)
2218
+ parseFlexFile (token);
2219
+
2220
+ stringListDelete (ClassNames);
2221
+ stringListDelete (FunctionNames);
2222
+ ClassNames = NULL;
2223
+ FunctionNames = NULL;
2224
+ deleteToken (token);
2225
+ }
2226
+
2227
+ /* Create parser definition stucture */
2228
+ extern parserDefinition* FlexParser (void)
2229
+ {
2230
+ static const char *const extensions [] = { "as", "mxml", NULL };
2231
+ parserDefinition *const def = parserNew ("Flex");
2232
+ def->extensions = extensions;
2233
+ /*
2234
+ * New definitions for parsing instead of regex
2235
+ */
2236
+ def->kinds = FlexKinds;
2237
+ def->kindCount = KIND_COUNT (FlexKinds);
2238
+ def->parser = findFlexTags;
2239
+ def->initialize = initialize;
2240
+
2241
+ return def;
2242
+ }
2243
+ /* vi:set tabstop=4 shiftwidth=4 noexpandtab: */