1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
46 #include "qdeclarativejslexer_p.h"
48 #include "qdeclarativejsglobal_p.h"
49 #include "qdeclarativejsengine_p.h"
50 #include "qdeclarativejsgrammar_p.h"
52 #include <QtCore/qcoreapplication.h>
60 Q_CORE_EXPORT double qstrtod(const char *s00, char const **se, bool *ok);
63 QT_QML_BEGIN_NAMESPACE
65 #define shiftWindowsLineBreak() \
67 if (((current == '\r') && (next1 == '\n')) \
68 || ((current == '\n') && (next1 == '\r'))) { \
74 namespace QDeclarativeJS {
75 extern double integerFromString(const char *buf, int size, int radix);
78 using namespace QDeclarativeJS;
80 Lexer::Lexer(Engine *eng, bool tokenizeComments)
84 size8(128), size16(128),
95 startlineno(0), startcolumn(0),
97 current(0), next1(0), next2(0), next3(0),
100 check_reserved(true),
101 parenthesesState(IgnoreParentheses),
103 prohibitAutomaticSemicolon(false),
104 tokenizeComments(tokenizeComments)
106 if (driver) driver->setLexer(this);
107 // allocate space for read buffers
108 buffer8 = new char[size8];
109 buffer16 = new QChar[size16];
121 void Lexer::setCode(const QString &c, int lineno)
126 restrKeyword = false;
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;
141 void Lexer::shift(uint p)
149 next3 = (pos + 3 < length) ? code[pos+3].unicode() : 0;
153 void Lexer::setDone(State s)
159 int Lexer::findReservedWord(const QChar *c, int size) const
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
473 ushort stringType = 0; // either single or double quotes
474 bool multiLineString = false;
479 // did we push a token on the stack previously ?
480 // (after an automatic semicolon insertion)
481 if (stackToken >= 0) {
487 bool identifierWithEscapedUnicode = false;
492 if (isWhiteSpace()) {
494 } else if (current == '/' && next1 == '/') {
497 state = InSingleLineComment;
498 } else if (current == '/' && next1 == '*') {
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;
512 } else if (isLineTerminator()) {
514 // automatic semicolon insertion
516 token = QDeclarativeJSGrammar::T_SEMICOLON;
519 shiftWindowsLineBreak();
524 syncProhibitAutomaticSemicolon();
526 } else if (current == '"' || current == '\'') {
529 multiLineString = false;
530 stringType = current;
531 } else if (current == '\\' && next1 == 'u') {
532 identifierWithEscapedUnicode = true;
535 shift(2); // skip the unicode escape prefix `\u'
537 if (isHexDigit(current) && isHexDigit(next1) &&
538 isHexDigit(next2) && isHexDigit(next3)) {
539 record16(convertUnicode(current, next1, next2, next3));
541 state = InIdentifier;
544 err = IllegalUnicodeEscapeSequence;
545 errmsg = QCoreApplication::translate("QDeclarativeParser", "Illegal unicode escape sequence");
549 } else if (isIdentLetter(current)) {
550 identifierWithEscapedUnicode = false;
553 state = InIdentifier;
554 } else if (current == '0') {
558 } else if (isDecimalDigit(current)) {
562 } else if (current == '.' && isDecimalDigit(next1)) {
568 token = matchPunctuator(current, next1, next2, next3);
570 if (terminator && !delimited && !prohibitAutomaticSemicolon
571 && (token == QDeclarativeJSGrammar::T_PLUS_PLUS
572 || token == QDeclarativeJSGrammar::T_MINUS_MINUS)) {
573 // automatic semicolon insertion
575 token = QDeclarativeJSGrammar::T_SEMICOLON;
581 err = IllegalCharacter;
582 errmsg = QCoreApplication::translate("QDeclarativeParser", "Illegal character");
587 if (current == stringType) {
590 } else if (isLineTerminator()) {
591 multiLineString = true;
593 } else if (current == 0 || isLineTerminator()) {
595 err = UnclosedStringLiteral;
596 errmsg = QCoreApplication::translate("QDeclarativeParser", "Unclosed string at end of line");
597 } else if (current == '\\') {
598 state = InEscapeSequence;
603 // Escape Sequences inside of strings
604 case InEscapeSequence:
605 if (isOctalDigit(current)) {
606 if (current >= '0' && current <= '3' &&
607 isOctalDigit(next1) && isOctalDigit(next2)) {
608 record16(convertOctal(current, next1, next2));
611 } else if (isOctalDigit(current) &&
612 isOctalDigit(next1)) {
613 record16(convertOctal('0', current, next1));
616 } else if (isOctalDigit(current)) {
617 record16(convertOctal('0', '0', current));
621 err = IllegalEscapeSequence;
622 errmsg = QCoreApplication::translate("QDeclarativeParser", "Illegal escape sequence");
624 } else if (current == 'x')
626 else if (current == 'u')
627 state = InUnicodeEscape;
629 if (isLineTerminator()) {
630 shiftWindowsLineBreak();
635 record16(singleEscape(current));
641 if (isHexDigit(current) && isHexDigit(next1)) {
643 record16(QLatin1Char(convertHex(current, next1)));
645 } else if (current == stringType) {
646 record16(QLatin1Char('x'));
650 record16(QLatin1Char('x'));
655 case InUnicodeEscape:
656 if (isHexDigit(current) && isHexDigit(next1) &&
657 isHexDigit(next2) && isHexDigit(next3)) {
658 record16(convertUnicode(current, next1, next2, next3));
661 } else if (current == stringType) {
662 record16(QLatin1Char('u'));
667 err = IllegalUnicodeEscapeSequence;
668 errmsg = QCoreApplication::translate("QDeclarativeParser", "Illegal unicode escape sequence");
671 case InSingleLineComment:
672 if (isLineTerminator()) {
673 shiftWindowsLineBreak();
679 token = QDeclarativeJSGrammar::T_SEMICOLON;
683 if (driver) driver->addComment(startpos+2, tokenLength()-2, startlineno, startcolumn+2);
684 } else if (current == 0) {
685 if (driver) driver->addComment(startpos+2, tokenLength()-2, startlineno, startcolumn+2);
690 case InMultiLineComment:
693 err = UnclosedComment;
694 errmsg = QCoreApplication::translate("QDeclarativeParser", "Unclosed comment at end of file");
695 if (driver) driver->addComment(startpos+2, tokenLength()-2, startlineno, startcolumn+2);
696 } else if (isLineTerminator()) {
697 shiftWindowsLineBreak();
699 } else if (current == '*' && next1 == '/') {
702 if (driver) driver->addComment(startpos+2, tokenLength()-3, startlineno, startcolumn+2);
707 if (isIdentLetter(current) || isDecimalDigit(current)) {
710 } else if (current == '\\' && next1 == 'u') {
711 identifierWithEscapedUnicode = true;
712 shift(2); // skip the unicode escape prefix `\u'
714 if (isHexDigit(current) && isHexDigit(next1) &&
715 isHexDigit(next2) && isHexDigit(next3)) {
716 record16(convertUnicode(current, next1, next2, next3));
721 err = IllegalUnicodeEscapeSequence;
722 errmsg = QCoreApplication::translate("QDeclarativeParser", "Illegal unicode escape sequence");
729 if (current == 'x' || current == 'X') {
732 } else if (current == '.') {
735 } else if (current == 'e' || current == 'E') {
737 state = InExponentIndicator;
738 } else if (isOctalDigit(current)) {
741 } else if (isDecimalDigit(current)) {
749 if (isHexDigit(current))
755 if (isOctalDigit(current)) {
757 } else if (isDecimalDigit(current)) {
765 if (isDecimalDigit(current)) {
767 } else if (current == '.') {
770 } else if (current == 'e' || current == 'E') {
772 state = InExponentIndicator;
778 if (isDecimalDigit(current)) {
780 } else if (current == 'e' || current == 'E') {
782 state = InExponentIndicator;
787 case InExponentIndicator:
788 if (current == '+' || current == '-') {
790 } else if (isDecimalDigit(current)) {
795 err = IllegalExponentIndicator;
796 errmsg = QCoreApplication::translate("QDeclarativeParser", "Illegal syntax for exponential number");
800 if (isDecimalDigit(current)) {
807 Q_ASSERT_X(0, "Lexer::lex", "Unhandled state in switch statement");
810 // move on to the next character
813 if (state != Start && state != InSingleLineComment)
817 // no identifiers allowed directly after numeric literal, e.g. "3in" is bad
818 if ((state == Number || state == Octal || state == Hex)
819 && isIdentLetter(current)) {
821 err = IllegalIdentifier;
822 errmsg = QCoreApplication::translate("QDeclarativeParser", "Identifier cannot start with numeric literal");
826 buffer8[pos8] = '\0';
829 if (state == Number) {
830 dval = qstrtod(buffer8, 0, 0);
831 } else if (state == Hex) { // scan hex numbers
832 dval = integerFromString(buffer8, pos8, 16);
834 } else if (state == Octal) { // scan octal number
835 dval = integerFromString(buffer8, pos8, 8);
839 restrKeyword = false;
842 switch (parenthesesState) {
843 case IgnoreParentheses:
845 case CountParentheses:
846 if (token == QDeclarativeJSGrammar::T_RPAREN) {
848 if (parenthesesCount == 0)
849 parenthesesState = BalancedParentheses;
850 } else if (token == QDeclarativeJSGrammar::T_LPAREN) {
854 case BalancedParentheses:
855 parenthesesState = IgnoreParentheses;
863 if (token == QDeclarativeJSGrammar::T_RBRACE || token == QDeclarativeJSGrammar::T_SEMICOLON)
868 if (! identifierWithEscapedUnicode)
869 token = findReservedWord(buffer16, pos16);
872 /* TODO: close leak on parse error. same holds true for String */
874 qsyylval.ustr = driver->intern(buffer16, pos16);
877 return QDeclarativeJSGrammar::T_IDENTIFIER;
879 if (token == QDeclarativeJSGrammar::T_CONTINUE || token == QDeclarativeJSGrammar::T_BREAK
880 || token == QDeclarativeJSGrammar::T_RETURN || token == QDeclarativeJSGrammar::T_THROW) {
882 } else if (token == QDeclarativeJSGrammar::T_IF || token == QDeclarativeJSGrammar::T_FOR
883 || token == QDeclarativeJSGrammar::T_WHILE || token == QDeclarativeJSGrammar::T_WITH) {
884 parenthesesState = CountParentheses;
885 parenthesesCount = 0;
886 } else if (token == QDeclarativeJSGrammar::T_DO) {
887 parenthesesState = BalancedParentheses;
892 qsyylval.ustr = driver->intern(buffer16, pos16);
895 return multiLineString?QDeclarativeJSGrammar::T_MULTILINE_STRING_LITERAL:QDeclarativeJSGrammar::T_STRING_LITERAL;
897 qsyylval.dval = dval;
898 return QDeclarativeJSGrammar::T_NUMERIC_LITERAL;
902 Q_ASSERT(!"unhandled numeration value in switch");
907 bool Lexer::isWhiteSpace() const
909 return (current == ' ' || current == '\t' ||
910 current == 0x0b || current == 0x0c);
913 bool Lexer::isLineTerminator() const
915 return (current == '\n' || current == '\r');
918 bool Lexer::isIdentLetter(ushort c)
920 // ASCII-biased, since all reserved words are ASCII, aand hence the
921 // bulk of content to be parsed.
922 if ((c >= 'a' && c <= 'z')
923 || (c >= 'A' && c <= 'Z')
929 return QChar(c).isLetterOrNumber();
932 bool Lexer::isDecimalDigit(ushort c)
934 return (c >= '0' && c <= '9');
937 bool Lexer::isHexDigit(ushort c) const
939 return ((c >= '0' && c <= '9')
940 || (c >= 'a' && c <= 'f')
941 || (c >= 'A' && c <= 'F'));
944 bool Lexer::isOctalDigit(ushort c) const
946 return (c >= '0' && c <= '7');
949 int Lexer::matchPunctuator(ushort c1, ushort c2,
950 ushort c3, ushort c4)
952 if (c1 == '>' && c2 == '>' && c3 == '>' && c4 == '=') {
954 return QDeclarativeJSGrammar::T_GT_GT_GT_EQ;
955 } else if (c1 == '=' && c2 == '=' && c3 == '=') {
957 return QDeclarativeJSGrammar::T_EQ_EQ_EQ;
958 } else if (c1 == '!' && c2 == '=' && c3 == '=') {
960 return QDeclarativeJSGrammar::T_NOT_EQ_EQ;
961 } else if (c1 == '>' && c2 == '>' && c3 == '>') {
963 return QDeclarativeJSGrammar::T_GT_GT_GT;
964 } else if (c1 == '<' && c2 == '<' && c3 == '=') {
966 return QDeclarativeJSGrammar::T_LT_LT_EQ;
967 } else if (c1 == '>' && c2 == '>' && c3 == '=') {
969 return QDeclarativeJSGrammar::T_GT_GT_EQ;
970 } else if (c1 == '<' && c2 == '=') {
972 return QDeclarativeJSGrammar::T_LE;
973 } else if (c1 == '>' && c2 == '=') {
975 return QDeclarativeJSGrammar::T_GE;
976 } else if (c1 == '!' && c2 == '=') {
978 return QDeclarativeJSGrammar::T_NOT_EQ;
979 } else if (c1 == '+' && c2 == '+') {
981 return QDeclarativeJSGrammar::T_PLUS_PLUS;
982 } else if (c1 == '-' && c2 == '-') {
984 return QDeclarativeJSGrammar::T_MINUS_MINUS;
985 } else if (c1 == '=' && c2 == '=') {
987 return QDeclarativeJSGrammar::T_EQ_EQ;
988 } else if (c1 == '+' && c2 == '=') {
990 return QDeclarativeJSGrammar::T_PLUS_EQ;
991 } else if (c1 == '-' && c2 == '=') {
993 return QDeclarativeJSGrammar::T_MINUS_EQ;
994 } else if (c1 == '*' && c2 == '=') {
996 return QDeclarativeJSGrammar::T_STAR_EQ;
997 } else if (c1 == '/' && c2 == '=') {
999 return QDeclarativeJSGrammar::T_DIVIDE_EQ;
1000 } else if (c1 == '&' && c2 == '=') {
1002 return QDeclarativeJSGrammar::T_AND_EQ;
1003 } else if (c1 == '^' && c2 == '=') {
1005 return QDeclarativeJSGrammar::T_XOR_EQ;
1006 } else if (c1 == '%' && c2 == '=') {
1008 return QDeclarativeJSGrammar::T_REMAINDER_EQ;
1009 } else if (c1 == '|' && c2 == '=') {
1011 return QDeclarativeJSGrammar::T_OR_EQ;
1012 } else if (c1 == '<' && c2 == '<') {
1014 return QDeclarativeJSGrammar::T_LT_LT;
1015 } else if (c1 == '>' && c2 == '>') {
1017 return QDeclarativeJSGrammar::T_GT_GT;
1018 } else if (c1 == '&' && c2 == '&') {
1020 return QDeclarativeJSGrammar::T_AND_AND;
1021 } else if (c1 == '|' && c2 == '|') {
1023 return QDeclarativeJSGrammar::T_OR_OR;
1027 case '=': shift(1); return QDeclarativeJSGrammar::T_EQ;
1028 case '>': shift(1); return QDeclarativeJSGrammar::T_GT;
1029 case '<': shift(1); return QDeclarativeJSGrammar::T_LT;
1030 case ',': shift(1); return QDeclarativeJSGrammar::T_COMMA;
1031 case '!': shift(1); return QDeclarativeJSGrammar::T_NOT;
1032 case '~': shift(1); return QDeclarativeJSGrammar::T_TILDE;
1033 case '?': shift(1); return QDeclarativeJSGrammar::T_QUESTION;
1034 case ':': shift(1); return QDeclarativeJSGrammar::T_COLON;
1035 case '.': shift(1); return QDeclarativeJSGrammar::T_DOT;
1036 case '+': shift(1); return QDeclarativeJSGrammar::T_PLUS;
1037 case '-': shift(1); return QDeclarativeJSGrammar::T_MINUS;
1038 case '*': shift(1); return QDeclarativeJSGrammar::T_STAR;
1039 case '/': shift(1); return QDeclarativeJSGrammar::T_DIVIDE_;
1040 case '&': shift(1); return QDeclarativeJSGrammar::T_AND;
1041 case '|': shift(1); return QDeclarativeJSGrammar::T_OR;
1042 case '^': shift(1); return QDeclarativeJSGrammar::T_XOR;
1043 case '%': shift(1); return QDeclarativeJSGrammar::T_REMAINDER;
1044 case '(': shift(1); return QDeclarativeJSGrammar::T_LPAREN;
1045 case ')': shift(1); return QDeclarativeJSGrammar::T_RPAREN;
1046 case '{': shift(1); return QDeclarativeJSGrammar::T_LBRACE;
1047 case '}': shift(1); return QDeclarativeJSGrammar::T_RBRACE;
1048 case '[': shift(1); return QDeclarativeJSGrammar::T_LBRACKET;
1049 case ']': shift(1); return QDeclarativeJSGrammar::T_RBRACKET;
1050 case ';': shift(1); return QDeclarativeJSGrammar::T_SEMICOLON;
1056 ushort Lexer::singleEscape(ushort c) const
1082 ushort Lexer::convertOctal(ushort c1, ushort c2,
1085 return ((c1 - '0') * 64 + (c2 - '0') * 8 + c3 - '0');
1088 unsigned char Lexer::convertHex(ushort c)
1090 if (c >= '0' && c <= '9')
1092 else if (c >= 'a' && c <= 'f')
1093 return (c - 'a' + 10);
1095 return (c - 'A' + 10);
1098 unsigned char Lexer::convertHex(ushort c1, ushort c2)
1100 return ((convertHex(c1) << 4) + convertHex(c2));
1103 QChar Lexer::convertUnicode(ushort c1, ushort c2,
1104 ushort c3, ushort c4)
1106 return QChar((convertHex(c3) << 4) + convertHex(c4),
1107 (convertHex(c1) << 4) + convertHex(c2));
1110 void Lexer::record8(ushort c)
1112 Q_ASSERT(c <= 0xff);
1114 // enlarge buffer if full
1115 if (pos8 >= size8 - 1) {
1116 char *tmp = new char[2 * size8];
1117 memcpy(tmp, buffer8, size8 * sizeof(char));
1123 buffer8[pos8++] = (char) c;
1126 void Lexer::record16(QChar c)
1128 // enlarge buffer if full
1129 if (pos16 >= size16 - 1) {
1130 QChar *tmp = new QChar[2 * size16];
1131 memcpy(tmp, buffer16, size16 * sizeof(QChar));
1137 buffer16[pos16++] = c;
1140 void Lexer::recordStartPos()
1143 startlineno = yylineno;
1144 startcolumn = yycolumn;
1147 bool Lexer::scanRegExp(RegExpBodyPrefix prefix)
1152 if (prefix == EqualPrefix)
1153 record16(QLatin1Char('='));
1159 case '\n': case '\r': // line terminator
1160 errmsg = QCoreApplication::translate("QDeclarativeParser", "Unterminated regular expression literal");
1166 if (driver) // create the pattern
1167 pattern = driver->intern(buffer16, pos16);
1172 while (isIdentLetter(current)) {
1173 int flag = Ecma::RegExp::flagFromChar(current);
1175 errmsg = QCoreApplication::translate("QDeclarativeParser", "Invalid regular expression flag '%0'")
1176 .arg(QChar(current));
1186 // regular expression backslash sequence
1190 if (! current || isLineTerminator()) {
1191 errmsg = QCoreApplication::translate("QDeclarativeParser", "Unterminated regular expression backslash sequence");
1200 // regular expression class
1204 while (current && ! isLineTerminator()) {
1207 else if (current == '\\') {
1208 // regular expression backslash sequence
1212 if (! current || isLineTerminator()) {
1213 errmsg = QCoreApplication::translate("QDeclarativeParser", "Unterminated regular expression backslash sequence");
1225 if (current != ']') {
1226 errmsg = QCoreApplication::translate("QDeclarativeParser", "Unterminated regular expression class");
1243 void Lexer::syncProhibitAutomaticSemicolon()
1245 if (parenthesesState == BalancedParentheses) {
1246 // we have seen something like "if (foo)", which means we should
1247 // never insert an automatic semicolon at this point, since it would
1248 // then be expanded into an empty statement (ECMA-262 7.9.1)
1249 prohibitAutomaticSemicolon = true;
1250 parenthesesState = IgnoreParentheses;
1252 prohibitAutomaticSemicolon = false;
1256 QT_QML_END_NAMESPACE