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.
- data/Gemfile +2 -0
- data/Rakefile +23 -0
- data/ctags.rb.gemspec +23 -0
- data/ext/.gitignore +3 -0
- data/ext/extconf.rb +15 -0
- data/ext/vendor/exuberant-ctags/.gitignore +6 -0
- data/ext/vendor/exuberant-ctags/.indent.pro +31 -0
- data/ext/vendor/exuberant-ctags/COPYING +340 -0
- data/ext/vendor/exuberant-ctags/EXTENDING.html +386 -0
- data/ext/vendor/exuberant-ctags/FAQ +371 -0
- data/ext/vendor/exuberant-ctags/INSTALL +215 -0
- data/ext/vendor/exuberant-ctags/INSTALL.oth +73 -0
- data/ext/vendor/exuberant-ctags/MAINTAINERS +88 -0
- data/ext/vendor/exuberant-ctags/Makefile.in +222 -0
- data/ext/vendor/exuberant-ctags/NEWS +871 -0
- data/ext/vendor/exuberant-ctags/README +73 -0
- data/ext/vendor/exuberant-ctags/ant.c +42 -0
- data/ext/vendor/exuberant-ctags/argproc.c +505 -0
- data/ext/vendor/exuberant-ctags/args.c +274 -0
- data/ext/vendor/exuberant-ctags/args.h +63 -0
- data/ext/vendor/exuberant-ctags/asm.c +387 -0
- data/ext/vendor/exuberant-ctags/asp.c +328 -0
- data/ext/vendor/exuberant-ctags/awk.c +81 -0
- data/ext/vendor/exuberant-ctags/basic.c +203 -0
- data/ext/vendor/exuberant-ctags/beta.c +321 -0
- data/ext/vendor/exuberant-ctags/c.c +2932 -0
- data/ext/vendor/exuberant-ctags/cobol.c +50 -0
- data/ext/vendor/exuberant-ctags/config.h.in +277 -0
- data/ext/vendor/exuberant-ctags/configure +7704 -0
- data/ext/vendor/exuberant-ctags/configure.ac +532 -0
- data/ext/vendor/exuberant-ctags/ctags.1 +1186 -0
- data/ext/vendor/exuberant-ctags/ctags.h +28 -0
- data/ext/vendor/exuberant-ctags/ctags.html +2087 -0
- data/ext/vendor/exuberant-ctags/ctags.spec +40 -0
- data/ext/vendor/exuberant-ctags/debug.c +113 -0
- data/ext/vendor/exuberant-ctags/debug.h +70 -0
- data/ext/vendor/exuberant-ctags/descrip.mms +68 -0
- data/ext/vendor/exuberant-ctags/dosbatch.c +42 -0
- data/ext/vendor/exuberant-ctags/e_amiga.h +24 -0
- data/ext/vendor/exuberant-ctags/e_djgpp.h +47 -0
- data/ext/vendor/exuberant-ctags/e_mac.h +143 -0
- data/ext/vendor/exuberant-ctags/e_msoft.h +76 -0
- data/ext/vendor/exuberant-ctags/e_os2.h +37 -0
- data/ext/vendor/exuberant-ctags/e_qdos.h +34 -0
- data/ext/vendor/exuberant-ctags/e_riscos.h +58 -0
- data/ext/vendor/exuberant-ctags/e_vms.h +31 -0
- data/ext/vendor/exuberant-ctags/eiffel.c +1352 -0
- data/ext/vendor/exuberant-ctags/entry.c +847 -0
- data/ext/vendor/exuberant-ctags/entry.h +103 -0
- data/ext/vendor/exuberant-ctags/erlang.c +189 -0
- data/ext/vendor/exuberant-ctags/flex.c +2243 -0
- data/ext/vendor/exuberant-ctags/fortran.c +2197 -0
- data/ext/vendor/exuberant-ctags/general.h +127 -0
- data/ext/vendor/exuberant-ctags/get.c +669 -0
- data/ext/vendor/exuberant-ctags/get.h +50 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/.svn/all-wcprops +47 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/.svn/entries +112 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/README.txt.svn-base +5 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regcomp.c.svn-base +3818 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regex.c.svn-base +74 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regex.h.svn-base +575 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regex_internal.c.svn-base +1713 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regex_internal.h.svn-base +773 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/.svn/text-base/regexec.c.svn-base +4338 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/README.txt +5 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/regcomp.c +3818 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/regex.c +74 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/regex.h +575 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/regex_internal.c +1713 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/regex_internal.h +773 -0
- data/ext/vendor/exuberant-ctags/gnu_regex/regexec.c +4338 -0
- data/ext/vendor/exuberant-ctags/html.c +49 -0
- data/ext/vendor/exuberant-ctags/jscript.c +1572 -0
- data/ext/vendor/exuberant-ctags/keyword.c +258 -0
- data/ext/vendor/exuberant-ctags/keyword.h +34 -0
- data/ext/vendor/exuberant-ctags/lisp.c +139 -0
- data/ext/vendor/exuberant-ctags/lregex.c +704 -0
- data/ext/vendor/exuberant-ctags/lua.c +133 -0
- data/ext/vendor/exuberant-ctags/mac.c +273 -0
- data/ext/vendor/exuberant-ctags/magic.diff +21 -0
- data/ext/vendor/exuberant-ctags/main.c +584 -0
- data/ext/vendor/exuberant-ctags/main.h +32 -0
- data/ext/vendor/exuberant-ctags/maintainer.mak +476 -0
- data/ext/vendor/exuberant-ctags/make.c +217 -0
- data/ext/vendor/exuberant-ctags/matlab.c +44 -0
- data/ext/vendor/exuberant-ctags/mk_bc3.mak +46 -0
- data/ext/vendor/exuberant-ctags/mk_bc5.mak +49 -0
- data/ext/vendor/exuberant-ctags/mk_djg.mak +18 -0
- data/ext/vendor/exuberant-ctags/mk_manx.mak +65 -0
- data/ext/vendor/exuberant-ctags/mk_mingw.mak +31 -0
- data/ext/vendor/exuberant-ctags/mk_mpw.mak +130 -0
- data/ext/vendor/exuberant-ctags/mk_mvc.mak +40 -0
- data/ext/vendor/exuberant-ctags/mk_os2.mak +104 -0
- data/ext/vendor/exuberant-ctags/mk_qdos.mak +100 -0
- data/ext/vendor/exuberant-ctags/mk_sas.mak +63 -0
- data/ext/vendor/exuberant-ctags/mkinstalldirs +40 -0
- data/ext/vendor/exuberant-ctags/ocaml.c +1842 -0
- data/ext/vendor/exuberant-ctags/options.c +1842 -0
- data/ext/vendor/exuberant-ctags/options.h +155 -0
- data/ext/vendor/exuberant-ctags/parse.c +677 -0
- data/ext/vendor/exuberant-ctags/parse.h +129 -0
- data/ext/vendor/exuberant-ctags/parsers.h +63 -0
- data/ext/vendor/exuberant-ctags/pascal.c +267 -0
- data/ext/vendor/exuberant-ctags/perl.c +382 -0
- data/ext/vendor/exuberant-ctags/php.c +237 -0
- data/ext/vendor/exuberant-ctags/python.c +771 -0
- data/ext/vendor/exuberant-ctags/qdos.c +106 -0
- data/ext/vendor/exuberant-ctags/read.c +569 -0
- data/ext/vendor/exuberant-ctags/read.h +116 -0
- data/ext/vendor/exuberant-ctags/readtags.c +959 -0
- data/ext/vendor/exuberant-ctags/readtags.h +252 -0
- data/ext/vendor/exuberant-ctags/rexx.c +39 -0
- data/ext/vendor/exuberant-ctags/routines.c +891 -0
- data/ext/vendor/exuberant-ctags/routines.h +134 -0
- data/ext/vendor/exuberant-ctags/ruby.c +408 -0
- data/ext/vendor/exuberant-ctags/scheme.c +111 -0
- data/ext/vendor/exuberant-ctags/sh.c +115 -0
- data/ext/vendor/exuberant-ctags/slang.c +41 -0
- data/ext/vendor/exuberant-ctags/sml.c +212 -0
- data/ext/vendor/exuberant-ctags/sort.c +230 -0
- data/ext/vendor/exuberant-ctags/sort.h +32 -0
- data/ext/vendor/exuberant-ctags/source.mak +122 -0
- data/ext/vendor/exuberant-ctags/sql.c +2112 -0
- data/ext/vendor/exuberant-ctags/strlist.c +281 -0
- data/ext/vendor/exuberant-ctags/strlist.h +54 -0
- data/ext/vendor/exuberant-ctags/tcl.c +116 -0
- data/ext/vendor/exuberant-ctags/tex.c +524 -0
- data/ext/vendor/exuberant-ctags/verilog.c +340 -0
- data/ext/vendor/exuberant-ctags/vhdl.c +835 -0
- data/ext/vendor/exuberant-ctags/vim.c +636 -0
- data/ext/vendor/exuberant-ctags/vstring.c +232 -0
- data/ext/vendor/exuberant-ctags/vstring.h +85 -0
- data/ext/vendor/exuberant-ctags/yacc.c +40 -0
- data/lib/ctags/exuberant.rb +45 -0
- data/lib/ctags/version.rb +3 -0
- data/lib/ctags.rb +6 -0
- data/test/test_ctags.rb +24 -0
- 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: */
|