|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the QtDeclarative module of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 #ifdef HAVE_CONFIG_H |
|
43 #include <config.h> |
|
44 #endif |
|
45 |
|
46 #include "private/qdeclarativejslexer_p.h" |
|
47 |
|
48 #include "private/qdeclarativejsglobal_p.h" |
|
49 #include "private/qdeclarativejsengine_p.h" |
|
50 #include "private/qdeclarativejsgrammar_p.h" |
|
51 |
|
52 #include <QtCore/qcoreapplication.h> |
|
53 |
|
54 #include <ctype.h> |
|
55 #include <stdlib.h> |
|
56 #include <stdio.h> |
|
57 #include <string.h> |
|
58 |
|
59 QT_BEGIN_NAMESPACE |
|
60 Q_DECL_IMPORT extern double qstrtod(const char *s00, char const **se, bool *ok); |
|
61 QT_END_NAMESPACE |
|
62 |
|
63 QT_QML_BEGIN_NAMESPACE |
|
64 |
|
65 #define shiftWindowsLineBreak() \ |
|
66 do { \ |
|
67 if (((current == '\r') && (next1 == '\n')) \ |
|
68 || ((current == '\n') && (next1 == '\r'))) { \ |
|
69 shift(1); \ |
|
70 } \ |
|
71 } \ |
|
72 while (0) |
|
73 |
|
74 namespace QDeclarativeJS { |
|
75 extern double integerFromString(const char *buf, int size, int radix); |
|
76 } |
|
77 |
|
78 using namespace QDeclarativeJS; |
|
79 |
|
80 Lexer::Lexer(Engine *eng, bool tokenizeComments) |
|
81 : driver(eng), |
|
82 yylineno(0), |
|
83 done(false), |
|
84 size8(128), size16(128), |
|
85 pos8(0), pos16(0), |
|
86 terminator(false), |
|
87 restrKeyword(false), |
|
88 delimited(false), |
|
89 stackToken(-1), |
|
90 state(Start), |
|
91 pos(0), |
|
92 code(0), length(0), |
|
93 yycolumn(0), |
|
94 startpos(0), |
|
95 startlineno(0), startcolumn(0), |
|
96 bol(true), |
|
97 current(0), next1(0), next2(0), next3(0), |
|
98 err(NoError), |
|
99 wantRx(false), |
|
100 check_reserved(true), |
|
101 parenthesesState(IgnoreParentheses), |
|
102 parenthesesCount(0), |
|
103 prohibitAutomaticSemicolon(false), |
|
104 tokenizeComments(tokenizeComments) |
|
105 { |
|
106 driver->setLexer(this); |
|
107 // allocate space for read buffers |
|
108 buffer8 = new char[size8]; |
|
109 buffer16 = new QChar[size16]; |
|
110 pattern = 0; |
|
111 flags = 0; |
|
112 |
|
113 } |
|
114 |
|
115 Lexer::~Lexer() |
|
116 { |
|
117 delete [] buffer8; |
|
118 delete [] buffer16; |
|
119 } |
|
120 |
|
121 void Lexer::setCode(const QString &c, int lineno) |
|
122 { |
|
123 errmsg = QString(); |
|
124 yylineno = lineno; |
|
125 yycolumn = 1; |
|
126 restrKeyword = false; |
|
127 delimited = false; |
|
128 stackToken = -1; |
|
129 pos = 0; |
|
130 code = c.unicode(); |
|
131 length = c.length(); |
|
132 bol = true; |
|
133 |
|
134 // read first characters |
|
135 current = (length > 0) ? code[0].unicode() : 0; |
|
136 next1 = (length > 1) ? code[1].unicode() : 0; |
|
137 next2 = (length > 2) ? code[2].unicode() : 0; |
|
138 next3 = (length > 3) ? code[3].unicode() : 0; |
|
139 } |
|
140 |
|
141 void Lexer::shift(uint p) |
|
142 { |
|
143 while (p--) { |
|
144 ++pos; |
|
145 ++yycolumn; |
|
146 current = next1; |
|
147 next1 = next2; |
|
148 next2 = next3; |
|
149 next3 = (pos + 3 < length) ? code[pos+3].unicode() : 0; |
|
150 } |
|
151 } |
|
152 |
|
153 void Lexer::setDone(State s) |
|
154 { |
|
155 state = s; |
|
156 done = true; |
|
157 } |
|
158 |
|
159 int Lexer::findReservedWord(const QChar *c, int size) const |
|
160 { |
|
161 switch (size) { |
|
162 case 2: { |
|
163 if (c[0] == QLatin1Char('d') && c[1] == QLatin1Char('o')) |
|
164 return QDeclarativeJSGrammar::T_DO; |
|
165 else if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('f')) |
|
166 return QDeclarativeJSGrammar::T_IF; |
|
167 else if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('n')) |
|
168 return QDeclarativeJSGrammar::T_IN; |
|
169 else if (c[0] == QLatin1Char('a') && c[1] == QLatin1Char('s')) |
|
170 return QDeclarativeJSGrammar::T_AS; |
|
171 else if (c[0] == QLatin1Char('o') && c[1] == QLatin1Char('n')) |
|
172 return QDeclarativeJSGrammar::T_ON; |
|
173 } break; |
|
174 |
|
175 case 3: { |
|
176 if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('o') && c[2] == QLatin1Char('r')) |
|
177 return QDeclarativeJSGrammar::T_FOR; |
|
178 else if (c[0] == QLatin1Char('n') && c[1] == QLatin1Char('e') && c[2] == QLatin1Char('w')) |
|
179 return QDeclarativeJSGrammar::T_NEW; |
|
180 else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('r') && c[2] == QLatin1Char('y')) |
|
181 return QDeclarativeJSGrammar::T_TRY; |
|
182 else if (c[0] == QLatin1Char('v') && c[1] == QLatin1Char('a') && c[2] == QLatin1Char('r')) |
|
183 return QDeclarativeJSGrammar::T_VAR; |
|
184 else if (check_reserved) { |
|
185 if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('n') && c[2] == QLatin1Char('t')) |
|
186 return QDeclarativeJSGrammar::T_RESERVED_WORD; |
|
187 } |
|
188 } break; |
|
189 |
|
190 case 4: { |
|
191 if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('a') |
|
192 && c[2] == QLatin1Char('s') && c[3] == QLatin1Char('e')) |
|
193 return QDeclarativeJSGrammar::T_CASE; |
|
194 else if (c[0] == QLatin1Char('e') && c[1] == QLatin1Char('l') |
|
195 && c[2] == QLatin1Char('s') && c[3] == QLatin1Char('e')) |
|
196 return QDeclarativeJSGrammar::T_ELSE; |
|
197 else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('h') |
|
198 && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('s')) |
|
199 return QDeclarativeJSGrammar::T_THIS; |
|
200 else if (c[0] == QLatin1Char('v') && c[1] == QLatin1Char('o') |
|
201 && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('d')) |
|
202 return QDeclarativeJSGrammar::T_VOID; |
|
203 else if (c[0] == QLatin1Char('w') && c[1] == QLatin1Char('i') |
|
204 && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('h')) |
|
205 return QDeclarativeJSGrammar::T_WITH; |
|
206 else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('r') |
|
207 && c[2] == QLatin1Char('u') && c[3] == QLatin1Char('e')) |
|
208 return QDeclarativeJSGrammar::T_TRUE; |
|
209 else if (c[0] == QLatin1Char('n') && c[1] == QLatin1Char('u') |
|
210 && c[2] == QLatin1Char('l') && c[3] == QLatin1Char('l')) |
|
211 return QDeclarativeJSGrammar::T_NULL; |
|
212 else if (check_reserved) { |
|
213 if (c[0] == QLatin1Char('e') && c[1] == QLatin1Char('n') |
|
214 && c[2] == QLatin1Char('u') && c[3] == QLatin1Char('m')) |
|
215 return QDeclarativeJSGrammar::T_RESERVED_WORD; |
|
216 else if (c[0] == QLatin1Char('b') && c[1] == QLatin1Char('y') |
|
217 && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('e')) |
|
218 return QDeclarativeJSGrammar::T_RESERVED_WORD; |
|
219 else if (c[0] == QLatin1Char('l') && c[1] == QLatin1Char('o') |
|
220 && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('g')) |
|
221 return QDeclarativeJSGrammar::T_RESERVED_WORD; |
|
222 else if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('h') |
|
223 && c[2] == QLatin1Char('a') && c[3] == QLatin1Char('r')) |
|
224 return QDeclarativeJSGrammar::T_RESERVED_WORD; |
|
225 else if (c[0] == QLatin1Char('g') && c[1] == QLatin1Char('o') |
|
226 && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('o')) |
|
227 return QDeclarativeJSGrammar::T_RESERVED_WORD; |
|
228 } |
|
229 } break; |
|
230 |
|
231 case 5: { |
|
232 if (c[0] == QLatin1Char('b') && c[1] == QLatin1Char('r') |
|
233 && c[2] == QLatin1Char('e') && c[3] == QLatin1Char('a') |
|
234 && c[4] == QLatin1Char('k')) |
|
235 return QDeclarativeJSGrammar::T_BREAK; |
|
236 else if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('a') |
|
237 && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('c') |
|
238 && c[4] == QLatin1Char('h')) |
|
239 return QDeclarativeJSGrammar::T_CATCH; |
|
240 else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('h') |
|
241 && c[2] == QLatin1Char('r') && c[3] == QLatin1Char('o') |
|
242 && c[4] == QLatin1Char('w')) |
|
243 return QDeclarativeJSGrammar::T_THROW; |
|
244 else if (c[0] == QLatin1Char('w') && c[1] == QLatin1Char('h') |
|
245 && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('l') |
|
246 && c[4] == QLatin1Char('e')) |
|
247 return QDeclarativeJSGrammar::T_WHILE; |
|
248 else if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('o') |
|
249 && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('s') |
|
250 && c[4] == QLatin1Char('t')) |
|
251 return QDeclarativeJSGrammar::T_CONST; |
|
252 else if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('a') |
|
253 && c[2] == QLatin1Char('l') && c[3] == QLatin1Char('s') |
|
254 && c[4] == QLatin1Char('e')) |
|
255 return QDeclarativeJSGrammar::T_FALSE; |
|
256 else if (check_reserved) { |
|
257 if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('h') |
|
258 && c[2] == QLatin1Char('o') && c[3] == QLatin1Char('r') |
|
259 && c[4] == QLatin1Char('t')) |
|
260 return QDeclarativeJSGrammar::T_RESERVED_WORD; |
|
261 else if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('u') |
|
262 && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('e') |
|
263 && c[4] == QLatin1Char('r')) |
|
264 return QDeclarativeJSGrammar::T_RESERVED_WORD; |
|
265 else if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('i') |
|
266 && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('a') |
|
267 && c[4] == QLatin1Char('l')) |
|
268 return QDeclarativeJSGrammar::T_RESERVED_WORD; |
|
269 else if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('l') |
|
270 && c[2] == QLatin1Char('a') && c[3] == QLatin1Char('s') |
|
271 && c[4] == QLatin1Char('s')) |
|
272 return QDeclarativeJSGrammar::T_RESERVED_WORD; |
|
273 else if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('l') |
|
274 && c[2] == QLatin1Char('o') && c[3] == QLatin1Char('a') |
|
275 && c[4] == QLatin1Char('t')) |
|
276 return QDeclarativeJSGrammar::T_RESERVED_WORD; |
|
277 } |
|
278 } break; |
|
279 |
|
280 case 6: { |
|
281 if (c[0] == QLatin1Char('d') && c[1] == QLatin1Char('e') |
|
282 && c[2] == QLatin1Char('l') && c[3] == QLatin1Char('e') |
|
283 && c[4] == QLatin1Char('t') && c[5] == QLatin1Char('e')) |
|
284 return QDeclarativeJSGrammar::T_DELETE; |
|
285 else if (c[0] == QLatin1Char('r') && c[1] == QLatin1Char('e') |
|
286 && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('u') |
|
287 && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('n')) |
|
288 return QDeclarativeJSGrammar::T_RETURN; |
|
289 else if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('w') |
|
290 && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('t') |
|
291 && c[4] == QLatin1Char('c') && c[5] == QLatin1Char('h')) |
|
292 return QDeclarativeJSGrammar::T_SWITCH; |
|
293 else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('y') |
|
294 && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('e') |
|
295 && c[4] == QLatin1Char('o') && c[5] == QLatin1Char('f')) |
|
296 return QDeclarativeJSGrammar::T_TYPEOF; |
|
297 else if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('m') |
|
298 && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('o') |
|
299 && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('t')) |
|
300 return QDeclarativeJSGrammar::T_IMPORT; |
|
301 else if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('i') |
|
302 && c[2] == QLatin1Char('g') && c[3] == QLatin1Char('n') |
|
303 && c[4] == QLatin1Char('a') && c[5] == QLatin1Char('l')) |
|
304 return QDeclarativeJSGrammar::T_SIGNAL; |
|
305 else if (check_reserved) { |
|
306 if (c[0] == QLatin1Char('e') && c[1] == QLatin1Char('x') |
|
307 && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('o') |
|
308 && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('t')) |
|
309 return QDeclarativeJSGrammar::T_RESERVED_WORD; |
|
310 else if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('t') |
|
311 && c[2] == QLatin1Char('a') && c[3] == QLatin1Char('t') |
|
312 && c[4] == QLatin1Char('i') && c[5] == QLatin1Char('c')) |
|
313 return QDeclarativeJSGrammar::T_RESERVED_WORD; |
|
314 else if (c[0] == QLatin1Char('d') && c[1] == QLatin1Char('o') |
|
315 && c[2] == QLatin1Char('u') && c[3] == QLatin1Char('b') |
|
316 && c[4] == QLatin1Char('l') && c[5] == QLatin1Char('e')) |
|
317 return QDeclarativeJSGrammar::T_RESERVED_WORD; |
|
318 else if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('m') |
|
319 && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('o') |
|
320 && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('t')) |
|
321 return QDeclarativeJSGrammar::T_RESERVED_WORD; |
|
322 else if (c[0] == QLatin1Char('p') && c[1] == QLatin1Char('u') |
|
323 && c[2] == QLatin1Char('b') && c[3] == QLatin1Char('l') |
|
324 && c[4] == QLatin1Char('i') && c[5] == QLatin1Char('c')) |
|
325 return QDeclarativeJSGrammar::T_PUBLIC; |
|
326 else if (c[0] == QLatin1Char('n') && c[1] == QLatin1Char('a') |
|
327 && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('i') |
|
328 && c[4] == QLatin1Char('v') && c[5] == QLatin1Char('e')) |
|
329 return QDeclarativeJSGrammar::T_RESERVED_WORD; |
|
330 else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('h') |
|
331 && c[2] == QLatin1Char('r') && c[3] == QLatin1Char('o') |
|
332 && c[4] == QLatin1Char('w') && c[5] == QLatin1Char('s')) |
|
333 return QDeclarativeJSGrammar::T_RESERVED_WORD; |
|
334 } |
|
335 } break; |
|
336 |
|
337 case 7: { |
|
338 if (c[0] == QLatin1Char('d') && c[1] == QLatin1Char('e') |
|
339 && c[2] == QLatin1Char('f') && c[3] == QLatin1Char('a') |
|
340 && c[4] == QLatin1Char('u') && c[5] == QLatin1Char('l') |
|
341 && c[6] == QLatin1Char('t')) |
|
342 return QDeclarativeJSGrammar::T_DEFAULT; |
|
343 else if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('i') |
|
344 && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('a') |
|
345 && c[4] == QLatin1Char('l') && c[5] == QLatin1Char('l') |
|
346 && c[6] == QLatin1Char('y')) |
|
347 return QDeclarativeJSGrammar::T_FINALLY; |
|
348 else if (check_reserved) { |
|
349 if (c[0] == QLatin1Char('b') && c[1] == QLatin1Char('o') |
|
350 && c[2] == QLatin1Char('o') && c[3] == QLatin1Char('l') |
|
351 && c[4] == QLatin1Char('e') && c[5] == QLatin1Char('a') |
|
352 && c[6] == QLatin1Char('n')) |
|
353 return QDeclarativeJSGrammar::T_RESERVED_WORD; |
|
354 else if (c[0] == QLatin1Char('e') && c[1] == QLatin1Char('x') |
|
355 && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('e') |
|
356 && c[4] == QLatin1Char('n') && c[5] == QLatin1Char('d') |
|
357 && c[6] == QLatin1Char('s')) |
|
358 return QDeclarativeJSGrammar::T_RESERVED_WORD; |
|
359 else if (c[0] == QLatin1Char('p') && c[1] == QLatin1Char('a') |
|
360 && c[2] == QLatin1Char('c') && c[3] == QLatin1Char('k') |
|
361 && c[4] == QLatin1Char('a') && c[5] == QLatin1Char('g') |
|
362 && c[6] == QLatin1Char('e')) |
|
363 return QDeclarativeJSGrammar::T_RESERVED_WORD; |
|
364 else if (c[0] == QLatin1Char('p') && c[1] == QLatin1Char('r') |
|
365 && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('v') |
|
366 && c[4] == QLatin1Char('a') && c[5] == QLatin1Char('t') |
|
367 && c[6] == QLatin1Char('e')) |
|
368 return QDeclarativeJSGrammar::T_RESERVED_WORD; |
|
369 } |
|
370 } break; |
|
371 |
|
372 case 8: { |
|
373 if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('o') |
|
374 && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('t') |
|
375 && c[4] == QLatin1Char('i') && c[5] == QLatin1Char('n') |
|
376 && c[6] == QLatin1Char('u') && c[7] == QLatin1Char('e')) |
|
377 return QDeclarativeJSGrammar::T_CONTINUE; |
|
378 else if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('u') |
|
379 && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('c') |
|
380 && c[4] == QLatin1Char('t') && c[5] == QLatin1Char('i') |
|
381 && c[6] == QLatin1Char('o') && c[7] == QLatin1Char('n')) |
|
382 return QDeclarativeJSGrammar::T_FUNCTION; |
|
383 else if (c[0] == QLatin1Char('d') && c[1] == QLatin1Char('e') |
|
384 && c[2] == QLatin1Char('b') && c[3] == QLatin1Char('u') |
|
385 && c[4] == QLatin1Char('g') && c[5] == QLatin1Char('g') |
|
386 && c[6] == QLatin1Char('e') && c[7] == QLatin1Char('r')) |
|
387 return QDeclarativeJSGrammar::T_DEBUGGER; |
|
388 else if (c[0] == QLatin1Char('p') && c[1] == QLatin1Char('r') |
|
389 && c[2] == QLatin1Char('o') && c[3] == QLatin1Char('p') |
|
390 && c[4] == QLatin1Char('e') && c[5] == QLatin1Char('r') |
|
391 && c[6] == QLatin1Char('t') && c[7] == QLatin1Char('y')) |
|
392 return QDeclarativeJSGrammar::T_PROPERTY; |
|
393 else if (c[0] == QLatin1Char('r') && c[1] == QLatin1Char('e') |
|
394 && c[2] == QLatin1Char('a') && c[3] == QLatin1Char('d') |
|
395 && c[4] == QLatin1Char('o') && c[5] == QLatin1Char('n') |
|
396 && c[6] == QLatin1Char('l') && c[7] == QLatin1Char('y')) |
|
397 return QDeclarativeJSGrammar::T_READONLY; |
|
398 else if (check_reserved) { |
|
399 if (c[0] == QLatin1Char('a') && c[1] == QLatin1Char('b') |
|
400 && c[2] == QLatin1Char('s') && c[3] == QLatin1Char('t') |
|
401 && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('a') |
|
402 && c[6] == QLatin1Char('c') && c[7] == QLatin1Char('t')) |
|
403 return QDeclarativeJSGrammar::T_RESERVED_WORD; |
|
404 else if (c[0] == QLatin1Char('v') && c[1] == QLatin1Char('o') |
|
405 && c[2] == QLatin1Char('l') && c[3] == QLatin1Char('a') |
|
406 && c[4] == QLatin1Char('t') && c[5] == QLatin1Char('i') |
|
407 && c[6] == QLatin1Char('l') && c[7] == QLatin1Char('e')) |
|
408 return QDeclarativeJSGrammar::T_RESERVED_WORD; |
|
409 } |
|
410 } break; |
|
411 |
|
412 case 9: { |
|
413 if (check_reserved) { |
|
414 if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('n') |
|
415 && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('e') |
|
416 && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('f') |
|
417 && c[6] == QLatin1Char('a') && c[7] == QLatin1Char('c') |
|
418 && c[8] == QLatin1Char('e')) |
|
419 return QDeclarativeJSGrammar::T_RESERVED_WORD; |
|
420 else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('r') |
|
421 && c[2] == QLatin1Char('a') && c[3] == QLatin1Char('n') |
|
422 && c[4] == QLatin1Char('s') && c[5] == QLatin1Char('i') |
|
423 && c[6] == QLatin1Char('e') && c[7] == QLatin1Char('n') |
|
424 && c[8] == QLatin1Char('t')) |
|
425 return QDeclarativeJSGrammar::T_RESERVED_WORD; |
|
426 else if (c[0] == QLatin1Char('p') && c[1] == QLatin1Char('r') |
|
427 && c[2] == QLatin1Char('o') && c[3] == QLatin1Char('t') |
|
428 && c[4] == QLatin1Char('e') && c[5] == QLatin1Char('c') |
|
429 && c[6] == QLatin1Char('t') && c[7] == QLatin1Char('e') |
|
430 && c[8] == QLatin1Char('d')) |
|
431 return QDeclarativeJSGrammar::T_RESERVED_WORD; |
|
432 } |
|
433 } break; |
|
434 |
|
435 case 10: { |
|
436 if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('n') |
|
437 && c[2] == QLatin1Char('s') && c[3] == QLatin1Char('t') |
|
438 && c[4] == QLatin1Char('a') && c[5] == QLatin1Char('n') |
|
439 && c[6] == QLatin1Char('c') && c[7] == QLatin1Char('e') |
|
440 && c[8] == QLatin1Char('o') && c[9] == QLatin1Char('f')) |
|
441 return QDeclarativeJSGrammar::T_INSTANCEOF; |
|
442 else if (check_reserved) { |
|
443 if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('m') |
|
444 && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('l') |
|
445 && c[4] == QLatin1Char('e') && c[5] == QLatin1Char('m') |
|
446 && c[6] == QLatin1Char('e') && c[7] == QLatin1Char('n') |
|
447 && c[8] == QLatin1Char('t') && c[9] == QLatin1Char('s')) |
|
448 return QDeclarativeJSGrammar::T_RESERVED_WORD; |
|
449 } |
|
450 } break; |
|
451 |
|
452 case 12: { |
|
453 if (check_reserved) { |
|
454 if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('y') |
|
455 && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('c') |
|
456 && c[4] == QLatin1Char('h') && c[5] == QLatin1Char('r') |
|
457 && c[6] == QLatin1Char('o') && c[7] == QLatin1Char('n') |
|
458 && c[8] == QLatin1Char('i') && c[9] == QLatin1Char('z') |
|
459 && c[10] == QLatin1Char('e') && c[11] == QLatin1Char('d')) |
|
460 return QDeclarativeJSGrammar::T_RESERVED_WORD; |
|
461 } |
|
462 } break; |
|
463 |
|
464 } // switch |
|
465 |
|
466 return -1; |
|
467 } |
|
468 |
|
469 int Lexer::lex() |
|
470 { |
|
471 int token = 0; |
|
472 state = Start; |
|
473 ushort stringType = 0; // either single or double quotes |
|
474 bool multiLineString = false; |
|
475 pos8 = pos16 = 0; |
|
476 done = false; |
|
477 terminator = false; |
|
478 |
|
479 // did we push a token on the stack previously ? |
|
480 // (after an automatic semicolon insertion) |
|
481 if (stackToken >= 0) { |
|
482 setDone(Other); |
|
483 token = stackToken; |
|
484 stackToken = -1; |
|
485 } |
|
486 |
|
487 bool identifierWithEscapedUnicode = false; |
|
488 |
|
489 while (!done) { |
|
490 switch (state) { |
|
491 case Start: |
|
492 if (isWhiteSpace()) { |
|
493 // do nothing |
|
494 } else if (current == '/' && next1 == '/') { |
|
495 recordStartPos(); |
|
496 shift(1); |
|
497 state = InSingleLineComment; |
|
498 } else if (current == '/' && next1 == '*') { |
|
499 recordStartPos(); |
|
500 shift(1); |
|
501 state = InMultiLineComment; |
|
502 } else if (current == 0) { |
|
503 syncProhibitAutomaticSemicolon(); |
|
504 if (!terminator && !delimited && !prohibitAutomaticSemicolon) { |
|
505 // automatic semicolon insertion if program incomplete |
|
506 token = QDeclarativeJSGrammar::T_SEMICOLON; |
|
507 stackToken = 0; |
|
508 setDone(Other); |
|
509 } else { |
|
510 setDone(Eof); |
|
511 } |
|
512 } else if (isLineTerminator()) { |
|
513 shiftWindowsLineBreak(); |
|
514 yylineno++; |
|
515 yycolumn = 0; |
|
516 bol = true; |
|
517 terminator = true; |
|
518 syncProhibitAutomaticSemicolon(); |
|
519 if (restrKeyword) { |
|
520 token = QDeclarativeJSGrammar::T_SEMICOLON; |
|
521 setDone(Other); |
|
522 } |
|
523 } else if (current == '"' || current == '\'') { |
|
524 recordStartPos(); |
|
525 state = InString; |
|
526 multiLineString = false; |
|
527 stringType = current; |
|
528 } else if (current == '\\' && next1 == 'u') { |
|
529 identifierWithEscapedUnicode = true; |
|
530 recordStartPos(); |
|
531 |
|
532 shift(2); // skip the unicode escape prefix `\u' |
|
533 |
|
534 if (isHexDigit(current) && isHexDigit(next1) && |
|
535 isHexDigit(next2) && isHexDigit(next3)) { |
|
536 record16(convertUnicode(current, next1, next2, next3)); |
|
537 shift(3); |
|
538 state = InIdentifier; |
|
539 } else { |
|
540 setDone(Bad); |
|
541 err = IllegalUnicodeEscapeSequence; |
|
542 errmsg = QCoreApplication::translate("QDeclarativeParser", "Illegal unicode escape sequence"); |
|
543 break; |
|
544 } |
|
545 |
|
546 } else if (isIdentLetter(current)) { |
|
547 identifierWithEscapedUnicode = false; |
|
548 recordStartPos(); |
|
549 record16(current); |
|
550 state = InIdentifier; |
|
551 } else if (current == '0') { |
|
552 recordStartPos(); |
|
553 record8(current); |
|
554 state = InNum0; |
|
555 } else if (isDecimalDigit(current)) { |
|
556 recordStartPos(); |
|
557 record8(current); |
|
558 state = InNum; |
|
559 } else if (current == '.' && isDecimalDigit(next1)) { |
|
560 recordStartPos(); |
|
561 record8(current); |
|
562 state = InDecimal; |
|
563 } else { |
|
564 recordStartPos(); |
|
565 token = matchPunctuator(current, next1, next2, next3); |
|
566 if (token != -1) { |
|
567 if (terminator && !delimited && !prohibitAutomaticSemicolon |
|
568 && (token == QDeclarativeJSGrammar::T_PLUS_PLUS |
|
569 || token == QDeclarativeJSGrammar::T_MINUS_MINUS)) { |
|
570 // automatic semicolon insertion |
|
571 stackToken = token; |
|
572 token = QDeclarativeJSGrammar::T_SEMICOLON; |
|
573 } |
|
574 setDone(Other); |
|
575 } |
|
576 else { |
|
577 setDone(Bad); |
|
578 err = IllegalCharacter; |
|
579 errmsg = QCoreApplication::translate("QDeclarativeParser", "Illegal character"); |
|
580 } |
|
581 } |
|
582 break; |
|
583 case InString: |
|
584 if (current == stringType) { |
|
585 shift(1); |
|
586 setDone(String); |
|
587 } else if (isLineTerminator()) { |
|
588 multiLineString = true; |
|
589 record16(current); |
|
590 } else if (current == 0 || isLineTerminator()) { |
|
591 setDone(Bad); |
|
592 err = UnclosedStringLiteral; |
|
593 errmsg = QCoreApplication::translate("QDeclarativeParser", "Unclosed string at end of line"); |
|
594 } else if (current == '\\') { |
|
595 state = InEscapeSequence; |
|
596 } else { |
|
597 record16(current); |
|
598 } |
|
599 break; |
|
600 // Escape Sequences inside of strings |
|
601 case InEscapeSequence: |
|
602 if (isOctalDigit(current)) { |
|
603 if (current >= '0' && current <= '3' && |
|
604 isOctalDigit(next1) && isOctalDigit(next2)) { |
|
605 record16(convertOctal(current, next1, next2)); |
|
606 shift(2); |
|
607 state = InString; |
|
608 } else if (isOctalDigit(current) && |
|
609 isOctalDigit(next1)) { |
|
610 record16(convertOctal('0', current, next1)); |
|
611 shift(1); |
|
612 state = InString; |
|
613 } else if (isOctalDigit(current)) { |
|
614 record16(convertOctal('0', '0', current)); |
|
615 state = InString; |
|
616 } else { |
|
617 setDone(Bad); |
|
618 err = IllegalEscapeSequence; |
|
619 errmsg = QCoreApplication::translate("QDeclarativeParser", "Illegal escape squence"); |
|
620 } |
|
621 } else if (current == 'x') |
|
622 state = InHexEscape; |
|
623 else if (current == 'u') |
|
624 state = InUnicodeEscape; |
|
625 else { |
|
626 if (isLineTerminator()) { |
|
627 shiftWindowsLineBreak(); |
|
628 yylineno++; |
|
629 yycolumn = 0; |
|
630 bol = true; |
|
631 } else { |
|
632 record16(singleEscape(current)); |
|
633 } |
|
634 state = InString; |
|
635 } |
|
636 break; |
|
637 case InHexEscape: |
|
638 if (isHexDigit(current) && isHexDigit(next1)) { |
|
639 state = InString; |
|
640 record16(QLatin1Char(convertHex(current, next1))); |
|
641 shift(1); |
|
642 } else if (current == stringType) { |
|
643 record16(QLatin1Char('x')); |
|
644 shift(1); |
|
645 setDone(String); |
|
646 } else { |
|
647 record16(QLatin1Char('x')); |
|
648 record16(current); |
|
649 state = InString; |
|
650 } |
|
651 break; |
|
652 case InUnicodeEscape: |
|
653 if (isHexDigit(current) && isHexDigit(next1) && |
|
654 isHexDigit(next2) && isHexDigit(next3)) { |
|
655 record16(convertUnicode(current, next1, next2, next3)); |
|
656 shift(3); |
|
657 state = InString; |
|
658 } else if (current == stringType) { |
|
659 record16(QLatin1Char('u')); |
|
660 shift(1); |
|
661 setDone(String); |
|
662 } else { |
|
663 setDone(Bad); |
|
664 err = IllegalUnicodeEscapeSequence; |
|
665 errmsg = QCoreApplication::translate("QDeclarativeParser", "Illegal unicode escape sequence"); |
|
666 } |
|
667 break; |
|
668 case InSingleLineComment: |
|
669 if (isLineTerminator()) { |
|
670 shiftWindowsLineBreak(); |
|
671 yylineno++; |
|
672 yycolumn = 0; |
|
673 terminator = true; |
|
674 bol = true; |
|
675 if (restrKeyword) { |
|
676 token = QDeclarativeJSGrammar::T_SEMICOLON; |
|
677 setDone(Other); |
|
678 } else |
|
679 state = Start; |
|
680 driver->addComment(startpos, tokenLength(), startlineno, startcolumn); |
|
681 } else if (current == 0) { |
|
682 driver->addComment(startpos, tokenLength(), startlineno, startcolumn); |
|
683 setDone(Eof); |
|
684 } |
|
685 |
|
686 break; |
|
687 case InMultiLineComment: |
|
688 if (current == 0) { |
|
689 setDone(Bad); |
|
690 err = UnclosedComment; |
|
691 errmsg = QCoreApplication::translate("QDeclarativeParser", "Unclosed comment at end of file"); |
|
692 driver->addComment(startpos, tokenLength(), startlineno, startcolumn); |
|
693 } else if (isLineTerminator()) { |
|
694 shiftWindowsLineBreak(); |
|
695 yylineno++; |
|
696 } else if (current == '*' && next1 == '/') { |
|
697 state = Start; |
|
698 shift(1); |
|
699 driver->addComment(startpos, tokenLength(), startlineno, startcolumn); |
|
700 } |
|
701 |
|
702 break; |
|
703 case InIdentifier: |
|
704 if (isIdentLetter(current) || isDecimalDigit(current)) { |
|
705 record16(current); |
|
706 break; |
|
707 } else if (current == '\\' && next1 == 'u') { |
|
708 identifierWithEscapedUnicode = true; |
|
709 shift(2); // skip the unicode escape prefix `\u' |
|
710 |
|
711 if (isHexDigit(current) && isHexDigit(next1) && |
|
712 isHexDigit(next2) && isHexDigit(next3)) { |
|
713 record16(convertUnicode(current, next1, next2, next3)); |
|
714 shift(3); |
|
715 break; |
|
716 } else { |
|
717 setDone(Bad); |
|
718 err = IllegalUnicodeEscapeSequence; |
|
719 errmsg = QCoreApplication::translate("QDeclarativeParser", "Illegal unicode escape sequence"); |
|
720 break; |
|
721 } |
|
722 } |
|
723 setDone(Identifier); |
|
724 break; |
|
725 case InNum0: |
|
726 if (current == 'x' || current == 'X') { |
|
727 record8(current); |
|
728 state = InHex; |
|
729 } else if (current == '.') { |
|
730 record8(current); |
|
731 state = InDecimal; |
|
732 } else if (current == 'e' || current == 'E') { |
|
733 record8(current); |
|
734 state = InExponentIndicator; |
|
735 } else if (isOctalDigit(current)) { |
|
736 record8(current); |
|
737 state = InOctal; |
|
738 } else if (isDecimalDigit(current)) { |
|
739 record8(current); |
|
740 state = InDecimal; |
|
741 } else { |
|
742 setDone(Number); |
|
743 } |
|
744 break; |
|
745 case InHex: |
|
746 if (isHexDigit(current)) |
|
747 record8(current); |
|
748 else |
|
749 setDone(Hex); |
|
750 break; |
|
751 case InOctal: |
|
752 if (isOctalDigit(current)) { |
|
753 record8(current); |
|
754 } else if (isDecimalDigit(current)) { |
|
755 record8(current); |
|
756 state = InDecimal; |
|
757 } else { |
|
758 setDone(Octal); |
|
759 } |
|
760 break; |
|
761 case InNum: |
|
762 if (isDecimalDigit(current)) { |
|
763 record8(current); |
|
764 } else if (current == '.') { |
|
765 record8(current); |
|
766 state = InDecimal; |
|
767 } else if (current == 'e' || current == 'E') { |
|
768 record8(current); |
|
769 state = InExponentIndicator; |
|
770 } else { |
|
771 setDone(Number); |
|
772 } |
|
773 break; |
|
774 case InDecimal: |
|
775 if (isDecimalDigit(current)) { |
|
776 record8(current); |
|
777 } else if (current == 'e' || current == 'E') { |
|
778 record8(current); |
|
779 state = InExponentIndicator; |
|
780 } else { |
|
781 setDone(Number); |
|
782 } |
|
783 break; |
|
784 case InExponentIndicator: |
|
785 if (current == '+' || current == '-') { |
|
786 record8(current); |
|
787 } else if (isDecimalDigit(current)) { |
|
788 record8(current); |
|
789 state = InExponent; |
|
790 } else { |
|
791 setDone(Bad); |
|
792 err = IllegalExponentIndicator; |
|
793 errmsg = QCoreApplication::translate("QDeclarativeParser", "Illegal syntax for exponential number"); |
|
794 } |
|
795 break; |
|
796 case InExponent: |
|
797 if (isDecimalDigit(current)) { |
|
798 record8(current); |
|
799 } else { |
|
800 setDone(Number); |
|
801 } |
|
802 break; |
|
803 default: |
|
804 Q_ASSERT_X(0, "Lexer::lex", "Unhandled state in switch statement"); |
|
805 } |
|
806 |
|
807 // move on to the next character |
|
808 if (!done) |
|
809 shift(1); |
|
810 if (state != Start && state != InSingleLineComment) |
|
811 bol = false; |
|
812 } |
|
813 |
|
814 // no identifiers allowed directly after numeric literal, e.g. "3in" is bad |
|
815 if ((state == Number || state == Octal || state == Hex) |
|
816 && isIdentLetter(current)) { |
|
817 state = Bad; |
|
818 err = IllegalIdentifier; |
|
819 errmsg = QCoreApplication::translate("QDeclarativeParser", "Identifier cannot start with numeric literal"); |
|
820 } |
|
821 |
|
822 // terminate string |
|
823 buffer8[pos8] = '\0'; |
|
824 |
|
825 double dval = 0; |
|
826 if (state == Number) { |
|
827 dval = qstrtod(buffer8, 0, 0); |
|
828 } else if (state == Hex) { // scan hex numbers |
|
829 dval = integerFromString(buffer8, pos8, 16); |
|
830 state = Number; |
|
831 } else if (state == Octal) { // scan octal number |
|
832 dval = integerFromString(buffer8, pos8, 8); |
|
833 state = Number; |
|
834 } |
|
835 |
|
836 restrKeyword = false; |
|
837 delimited = false; |
|
838 |
|
839 switch (parenthesesState) { |
|
840 case IgnoreParentheses: |
|
841 break; |
|
842 case CountParentheses: |
|
843 if (token == QDeclarativeJSGrammar::T_RPAREN) { |
|
844 --parenthesesCount; |
|
845 if (parenthesesCount == 0) |
|
846 parenthesesState = BalancedParentheses; |
|
847 } else if (token == QDeclarativeJSGrammar::T_LPAREN) { |
|
848 ++parenthesesCount; |
|
849 } |
|
850 break; |
|
851 case BalancedParentheses: |
|
852 parenthesesState = IgnoreParentheses; |
|
853 break; |
|
854 } |
|
855 |
|
856 switch (state) { |
|
857 case Eof: |
|
858 return 0; |
|
859 case Other: |
|
860 if (token == QDeclarativeJSGrammar::T_RBRACE || token == QDeclarativeJSGrammar::T_SEMICOLON) |
|
861 delimited = true; |
|
862 return token; |
|
863 case Identifier: |
|
864 token = -1; |
|
865 if (! identifierWithEscapedUnicode) |
|
866 token = findReservedWord(buffer16, pos16); |
|
867 |
|
868 if (token < 0) { |
|
869 /* TODO: close leak on parse error. same holds true for String */ |
|
870 if (driver) |
|
871 qsyylval.ustr = driver->intern(buffer16, pos16); |
|
872 else |
|
873 qsyylval.ustr = 0; |
|
874 return QDeclarativeJSGrammar::T_IDENTIFIER; |
|
875 } |
|
876 if (token == QDeclarativeJSGrammar::T_CONTINUE || token == QDeclarativeJSGrammar::T_BREAK |
|
877 || token == QDeclarativeJSGrammar::T_RETURN || token == QDeclarativeJSGrammar::T_THROW) { |
|
878 restrKeyword = true; |
|
879 } else if (token == QDeclarativeJSGrammar::T_IF || token == QDeclarativeJSGrammar::T_FOR |
|
880 || token == QDeclarativeJSGrammar::T_WHILE || token == QDeclarativeJSGrammar::T_WITH) { |
|
881 parenthesesState = CountParentheses; |
|
882 parenthesesCount = 0; |
|
883 } else if (token == QDeclarativeJSGrammar::T_DO) { |
|
884 parenthesesState = BalancedParentheses; |
|
885 } |
|
886 return token; |
|
887 case String: |
|
888 if (driver) |
|
889 qsyylval.ustr = driver->intern(buffer16, pos16); |
|
890 else |
|
891 qsyylval.ustr = 0; |
|
892 return multiLineString?QDeclarativeJSGrammar::T_MULTILINE_STRING_LITERAL:QDeclarativeJSGrammar::T_STRING_LITERAL; |
|
893 case Number: |
|
894 qsyylval.dval = dval; |
|
895 return QDeclarativeJSGrammar::T_NUMERIC_LITERAL; |
|
896 case Bad: |
|
897 return -1; |
|
898 default: |
|
899 Q_ASSERT(!"unhandled numeration value in switch"); |
|
900 return -1; |
|
901 } |
|
902 } |
|
903 |
|
904 bool Lexer::isWhiteSpace() const |
|
905 { |
|
906 return (current == ' ' || current == '\t' || |
|
907 current == 0x0b || current == 0x0c); |
|
908 } |
|
909 |
|
910 bool Lexer::isLineTerminator() const |
|
911 { |
|
912 return (current == '\n' || current == '\r'); |
|
913 } |
|
914 |
|
915 bool Lexer::isIdentLetter(ushort c) |
|
916 { |
|
917 // ASCII-biased, since all reserved words are ASCII, aand hence the |
|
918 // bulk of content to be parsed. |
|
919 if ((c >= 'a' && c <= 'z') |
|
920 || (c >= 'A' && c <= 'Z') |
|
921 || c == '$' |
|
922 || c == '_') |
|
923 return true; |
|
924 if (c < 128) |
|
925 return false; |
|
926 return QChar(c).isLetterOrNumber(); |
|
927 } |
|
928 |
|
929 bool Lexer::isDecimalDigit(ushort c) |
|
930 { |
|
931 return (c >= '0' && c <= '9'); |
|
932 } |
|
933 |
|
934 bool Lexer::isHexDigit(ushort c) const |
|
935 { |
|
936 return ((c >= '0' && c <= '9') |
|
937 || (c >= 'a' && c <= 'f') |
|
938 || (c >= 'A' && c <= 'F')); |
|
939 } |
|
940 |
|
941 bool Lexer::isOctalDigit(ushort c) const |
|
942 { |
|
943 return (c >= '0' && c <= '7'); |
|
944 } |
|
945 |
|
946 int Lexer::matchPunctuator(ushort c1, ushort c2, |
|
947 ushort c3, ushort c4) |
|
948 { |
|
949 if (c1 == '>' && c2 == '>' && c3 == '>' && c4 == '=') { |
|
950 shift(4); |
|
951 return QDeclarativeJSGrammar::T_GT_GT_GT_EQ; |
|
952 } else if (c1 == '=' && c2 == '=' && c3 == '=') { |
|
953 shift(3); |
|
954 return QDeclarativeJSGrammar::T_EQ_EQ_EQ; |
|
955 } else if (c1 == '!' && c2 == '=' && c3 == '=') { |
|
956 shift(3); |
|
957 return QDeclarativeJSGrammar::T_NOT_EQ_EQ; |
|
958 } else if (c1 == '>' && c2 == '>' && c3 == '>') { |
|
959 shift(3); |
|
960 return QDeclarativeJSGrammar::T_GT_GT_GT; |
|
961 } else if (c1 == '<' && c2 == '<' && c3 == '=') { |
|
962 shift(3); |
|
963 return QDeclarativeJSGrammar::T_LT_LT_EQ; |
|
964 } else if (c1 == '>' && c2 == '>' && c3 == '=') { |
|
965 shift(3); |
|
966 return QDeclarativeJSGrammar::T_GT_GT_EQ; |
|
967 } else if (c1 == '<' && c2 == '=') { |
|
968 shift(2); |
|
969 return QDeclarativeJSGrammar::T_LE; |
|
970 } else if (c1 == '>' && c2 == '=') { |
|
971 shift(2); |
|
972 return QDeclarativeJSGrammar::T_GE; |
|
973 } else if (c1 == '!' && c2 == '=') { |
|
974 shift(2); |
|
975 return QDeclarativeJSGrammar::T_NOT_EQ; |
|
976 } else if (c1 == '+' && c2 == '+') { |
|
977 shift(2); |
|
978 return QDeclarativeJSGrammar::T_PLUS_PLUS; |
|
979 } else if (c1 == '-' && c2 == '-') { |
|
980 shift(2); |
|
981 return QDeclarativeJSGrammar::T_MINUS_MINUS; |
|
982 } else if (c1 == '=' && c2 == '=') { |
|
983 shift(2); |
|
984 return QDeclarativeJSGrammar::T_EQ_EQ; |
|
985 } else if (c1 == '+' && c2 == '=') { |
|
986 shift(2); |
|
987 return QDeclarativeJSGrammar::T_PLUS_EQ; |
|
988 } else if (c1 == '-' && c2 == '=') { |
|
989 shift(2); |
|
990 return QDeclarativeJSGrammar::T_MINUS_EQ; |
|
991 } else if (c1 == '*' && c2 == '=') { |
|
992 shift(2); |
|
993 return QDeclarativeJSGrammar::T_STAR_EQ; |
|
994 } else if (c1 == '/' && c2 == '=') { |
|
995 shift(2); |
|
996 return QDeclarativeJSGrammar::T_DIVIDE_EQ; |
|
997 } else if (c1 == '&' && c2 == '=') { |
|
998 shift(2); |
|
999 return QDeclarativeJSGrammar::T_AND_EQ; |
|
1000 } else if (c1 == '^' && c2 == '=') { |
|
1001 shift(2); |
|
1002 return QDeclarativeJSGrammar::T_XOR_EQ; |
|
1003 } else if (c1 == '%' && c2 == '=') { |
|
1004 shift(2); |
|
1005 return QDeclarativeJSGrammar::T_REMAINDER_EQ; |
|
1006 } else if (c1 == '|' && c2 == '=') { |
|
1007 shift(2); |
|
1008 return QDeclarativeJSGrammar::T_OR_EQ; |
|
1009 } else if (c1 == '<' && c2 == '<') { |
|
1010 shift(2); |
|
1011 return QDeclarativeJSGrammar::T_LT_LT; |
|
1012 } else if (c1 == '>' && c2 == '>') { |
|
1013 shift(2); |
|
1014 return QDeclarativeJSGrammar::T_GT_GT; |
|
1015 } else if (c1 == '&' && c2 == '&') { |
|
1016 shift(2); |
|
1017 return QDeclarativeJSGrammar::T_AND_AND; |
|
1018 } else if (c1 == '|' && c2 == '|') { |
|
1019 shift(2); |
|
1020 return QDeclarativeJSGrammar::T_OR_OR; |
|
1021 } |
|
1022 |
|
1023 switch(c1) { |
|
1024 case '=': shift(1); return QDeclarativeJSGrammar::T_EQ; |
|
1025 case '>': shift(1); return QDeclarativeJSGrammar::T_GT; |
|
1026 case '<': shift(1); return QDeclarativeJSGrammar::T_LT; |
|
1027 case ',': shift(1); return QDeclarativeJSGrammar::T_COMMA; |
|
1028 case '!': shift(1); return QDeclarativeJSGrammar::T_NOT; |
|
1029 case '~': shift(1); return QDeclarativeJSGrammar::T_TILDE; |
|
1030 case '?': shift(1); return QDeclarativeJSGrammar::T_QUESTION; |
|
1031 case ':': shift(1); return QDeclarativeJSGrammar::T_COLON; |
|
1032 case '.': shift(1); return QDeclarativeJSGrammar::T_DOT; |
|
1033 case '+': shift(1); return QDeclarativeJSGrammar::T_PLUS; |
|
1034 case '-': shift(1); return QDeclarativeJSGrammar::T_MINUS; |
|
1035 case '*': shift(1); return QDeclarativeJSGrammar::T_STAR; |
|
1036 case '/': shift(1); return QDeclarativeJSGrammar::T_DIVIDE_; |
|
1037 case '&': shift(1); return QDeclarativeJSGrammar::T_AND; |
|
1038 case '|': shift(1); return QDeclarativeJSGrammar::T_OR; |
|
1039 case '^': shift(1); return QDeclarativeJSGrammar::T_XOR; |
|
1040 case '%': shift(1); return QDeclarativeJSGrammar::T_REMAINDER; |
|
1041 case '(': shift(1); return QDeclarativeJSGrammar::T_LPAREN; |
|
1042 case ')': shift(1); return QDeclarativeJSGrammar::T_RPAREN; |
|
1043 case '{': shift(1); return QDeclarativeJSGrammar::T_LBRACE; |
|
1044 case '}': shift(1); return QDeclarativeJSGrammar::T_RBRACE; |
|
1045 case '[': shift(1); return QDeclarativeJSGrammar::T_LBRACKET; |
|
1046 case ']': shift(1); return QDeclarativeJSGrammar::T_RBRACKET; |
|
1047 case ';': shift(1); return QDeclarativeJSGrammar::T_SEMICOLON; |
|
1048 |
|
1049 default: return -1; |
|
1050 } |
|
1051 } |
|
1052 |
|
1053 ushort Lexer::singleEscape(ushort c) const |
|
1054 { |
|
1055 switch(c) { |
|
1056 case 'b': |
|
1057 return 0x08; |
|
1058 case 't': |
|
1059 return 0x09; |
|
1060 case 'n': |
|
1061 return 0x0A; |
|
1062 case 'v': |
|
1063 return 0x0B; |
|
1064 case 'f': |
|
1065 return 0x0C; |
|
1066 case 'r': |
|
1067 return 0x0D; |
|
1068 case '"': |
|
1069 return 0x22; |
|
1070 case '\'': |
|
1071 return 0x27; |
|
1072 case '\\': |
|
1073 return 0x5C; |
|
1074 default: |
|
1075 return c; |
|
1076 } |
|
1077 } |
|
1078 |
|
1079 ushort Lexer::convertOctal(ushort c1, ushort c2, |
|
1080 ushort c3) const |
|
1081 { |
|
1082 return ((c1 - '0') * 64 + (c2 - '0') * 8 + c3 - '0'); |
|
1083 } |
|
1084 |
|
1085 unsigned char Lexer::convertHex(ushort c) |
|
1086 { |
|
1087 if (c >= '0' && c <= '9') |
|
1088 return (c - '0'); |
|
1089 else if (c >= 'a' && c <= 'f') |
|
1090 return (c - 'a' + 10); |
|
1091 else |
|
1092 return (c - 'A' + 10); |
|
1093 } |
|
1094 |
|
1095 unsigned char Lexer::convertHex(ushort c1, ushort c2) |
|
1096 { |
|
1097 return ((convertHex(c1) << 4) + convertHex(c2)); |
|
1098 } |
|
1099 |
|
1100 QChar Lexer::convertUnicode(ushort c1, ushort c2, |
|
1101 ushort c3, ushort c4) |
|
1102 { |
|
1103 return QChar((convertHex(c3) << 4) + convertHex(c4), |
|
1104 (convertHex(c1) << 4) + convertHex(c2)); |
|
1105 } |
|
1106 |
|
1107 void Lexer::record8(ushort c) |
|
1108 { |
|
1109 Q_ASSERT(c <= 0xff); |
|
1110 |
|
1111 // enlarge buffer if full |
|
1112 if (pos8 >= size8 - 1) { |
|
1113 char *tmp = new char[2 * size8]; |
|
1114 memcpy(tmp, buffer8, size8 * sizeof(char)); |
|
1115 delete [] buffer8; |
|
1116 buffer8 = tmp; |
|
1117 size8 *= 2; |
|
1118 } |
|
1119 |
|
1120 buffer8[pos8++] = (char) c; |
|
1121 } |
|
1122 |
|
1123 void Lexer::record16(QChar c) |
|
1124 { |
|
1125 // enlarge buffer if full |
|
1126 if (pos16 >= size16 - 1) { |
|
1127 QChar *tmp = new QChar[2 * size16]; |
|
1128 memcpy(tmp, buffer16, size16 * sizeof(QChar)); |
|
1129 delete [] buffer16; |
|
1130 buffer16 = tmp; |
|
1131 size16 *= 2; |
|
1132 } |
|
1133 |
|
1134 buffer16[pos16++] = c; |
|
1135 } |
|
1136 |
|
1137 void Lexer::recordStartPos() |
|
1138 { |
|
1139 startpos = pos; |
|
1140 startlineno = yylineno; |
|
1141 startcolumn = yycolumn; |
|
1142 } |
|
1143 |
|
1144 bool Lexer::scanRegExp(RegExpBodyPrefix prefix) |
|
1145 { |
|
1146 pos16 = 0; |
|
1147 pattern = 0; |
|
1148 |
|
1149 if (prefix == EqualPrefix) |
|
1150 record16(QLatin1Char('=')); |
|
1151 |
|
1152 while (true) { |
|
1153 switch (current) { |
|
1154 |
|
1155 case 0: // eof |
|
1156 case '\n': case '\r': // line terminator |
|
1157 errmsg = QCoreApplication::translate("QDeclarativeParser", "Unterminated regular expression literal"); |
|
1158 return false; |
|
1159 |
|
1160 case '/': |
|
1161 shift(1); |
|
1162 |
|
1163 if (driver) // create the pattern |
|
1164 pattern = driver->intern(buffer16, pos16); |
|
1165 |
|
1166 // scan the flags |
|
1167 pos16 = 0; |
|
1168 flags = 0; |
|
1169 while (isIdentLetter(current)) { |
|
1170 int flag = Ecma::RegExp::flagFromChar(current); |
|
1171 if (flag == 0) { |
|
1172 errmsg = QCoreApplication::translate("QDeclarativeParser", "Invalid regular expression flag '%0'") |
|
1173 .arg(QChar(current)); |
|
1174 return false; |
|
1175 } |
|
1176 flags |= flag; |
|
1177 record16(current); |
|
1178 shift(1); |
|
1179 } |
|
1180 return true; |
|
1181 |
|
1182 case '\\': |
|
1183 // regular expression backslash sequence |
|
1184 record16(current); |
|
1185 shift(1); |
|
1186 |
|
1187 if (! current || isLineTerminator()) { |
|
1188 errmsg = QCoreApplication::translate("QDeclarativeParser", "Unterminated regular expression backslash sequence"); |
|
1189 return false; |
|
1190 } |
|
1191 |
|
1192 record16(current); |
|
1193 shift(1); |
|
1194 break; |
|
1195 |
|
1196 case '[': |
|
1197 // regular expression class |
|
1198 record16(current); |
|
1199 shift(1); |
|
1200 |
|
1201 while (current && ! isLineTerminator()) { |
|
1202 if (current == ']') |
|
1203 break; |
|
1204 else if (current == '\\') { |
|
1205 // regular expression backslash sequence |
|
1206 record16(current); |
|
1207 shift(1); |
|
1208 |
|
1209 if (! current || isLineTerminator()) { |
|
1210 errmsg = QCoreApplication::translate("QDeclarativeParser", "Unterminated regular expression backslash sequence"); |
|
1211 return false; |
|
1212 } |
|
1213 |
|
1214 record16(current); |
|
1215 shift(1); |
|
1216 } else { |
|
1217 record16(current); |
|
1218 shift(1); |
|
1219 } |
|
1220 } |
|
1221 |
|
1222 if (current != ']') { |
|
1223 errmsg = QCoreApplication::translate("QDeclarativeParser", "Unterminated regular expression class"); |
|
1224 return false; |
|
1225 } |
|
1226 |
|
1227 record16(current); |
|
1228 shift(1); // skip ] |
|
1229 break; |
|
1230 |
|
1231 default: |
|
1232 record16(current); |
|
1233 shift(1); |
|
1234 } // switch |
|
1235 } // while |
|
1236 |
|
1237 return false; |
|
1238 } |
|
1239 |
|
1240 void Lexer::syncProhibitAutomaticSemicolon() |
|
1241 { |
|
1242 if (parenthesesState == BalancedParentheses) { |
|
1243 // we have seen something like "if (foo)", which means we should |
|
1244 // never insert an automatic semicolon at this point, since it would |
|
1245 // then be expanded into an empty statement (ECMA-262 7.9.1) |
|
1246 prohibitAutomaticSemicolon = true; |
|
1247 parenthesesState = IgnoreParentheses; |
|
1248 } else { |
|
1249 prohibitAutomaticSemicolon = false; |
|
1250 } |
|
1251 } |
|
1252 |
|
1253 QT_QML_END_NAMESPACE |
|
1254 |
|
1255 |