ctags.rb 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: */