1 /**************************************************************************
3 ** This file is part of Qt Creator
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
7 ** Contact: Nokia Corporation (info@qt.nokia.com)
9 ** 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 file.
14 ** Please review the following information to ensure the GNU Lesser General
15 ** 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.
24 ** Alternatively, this file may be used in accordance with the terms and
25 ** conditions contained in a signed written agreement between you and Nokia.
27 ** If you have questions regarding the use of this file, please contact
28 ** Nokia at qt-info@nokia.com.
30 **************************************************************************/
36 #include "qmljslexer_p.h"
38 #include "qmljsglobal_p.h"
39 #include "qmljsengine_p.h"
40 #include "qmljsgrammar_p.h"
42 #include <QtCore/qcoreapplication.h>
50 Q_CORE_EXPORT double qstrtod(const char *s00, char const **se, bool *ok);
53 QT_QML_BEGIN_NAMESPACE
55 #define shiftWindowsLineBreak() \
57 if (((current == '\r') && (next1 == '\n')) \
58 || ((current == '\n') && (next1 == '\r'))) { \
65 extern double integerFromString(const char *buf, int size, int radix);
68 using namespace QmlJS;
70 Lexer::Lexer(Engine *eng, bool tokenizeComments)
74 size8(128), size16(128),
85 startlineno(0), startcolumn(0),
87 current(0), next1(0), next2(0), next3(0),
91 parenthesesState(IgnoreParentheses),
93 prohibitAutomaticSemicolon(false),
94 tokenizeComments(tokenizeComments)
96 if (driver) driver->setLexer(this);
97 // allocate space for read buffers
98 buffer8 = new char[size8];
99 buffer16 = new QChar[size16];
111 void Lexer::setCode(const QString &c, int lineno)
116 restrKeyword = false;
124 // read first characters
125 current = (length > 0) ? code[0].unicode() : 0;
126 next1 = (length > 1) ? code[1].unicode() : 0;
127 next2 = (length > 2) ? code[2].unicode() : 0;
128 next3 = (length > 3) ? code[3].unicode() : 0;
131 void Lexer::shift(uint p)
139 next3 = (pos + 3 < length) ? code[pos+3].unicode() : 0;
143 void Lexer::setDone(State s)
149 int Lexer::findReservedWord(const QChar *c, int size) const
153 if (c[0] == QLatin1Char('d') && c[1] == QLatin1Char('o'))
154 return QmlJSGrammar::T_DO;
155 else if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('f'))
156 return QmlJSGrammar::T_IF;
157 else if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('n'))
158 return QmlJSGrammar::T_IN;
159 else if (c[0] == QLatin1Char('a') && c[1] == QLatin1Char('s'))
160 return QmlJSGrammar::T_AS;
161 else if (c[0] == QLatin1Char('o') && c[1] == QLatin1Char('n'))
162 return QmlJSGrammar::T_ON;
166 if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('o') && c[2] == QLatin1Char('r'))
167 return QmlJSGrammar::T_FOR;
168 else if (c[0] == QLatin1Char('n') && c[1] == QLatin1Char('e') && c[2] == QLatin1Char('w'))
169 return QmlJSGrammar::T_NEW;
170 else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('r') && c[2] == QLatin1Char('y'))
171 return QmlJSGrammar::T_TRY;
172 else if (c[0] == QLatin1Char('v') && c[1] == QLatin1Char('a') && c[2] == QLatin1Char('r'))
173 return QmlJSGrammar::T_VAR;
174 else if (check_reserved) {
175 if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('n') && c[2] == QLatin1Char('t'))
176 return QmlJSGrammar::T_RESERVED_WORD;
181 if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('a')
182 && c[2] == QLatin1Char('s') && c[3] == QLatin1Char('e'))
183 return QmlJSGrammar::T_CASE;
184 else if (c[0] == QLatin1Char('e') && c[1] == QLatin1Char('l')
185 && c[2] == QLatin1Char('s') && c[3] == QLatin1Char('e'))
186 return QmlJSGrammar::T_ELSE;
187 else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('h')
188 && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('s'))
189 return QmlJSGrammar::T_THIS;
190 else if (c[0] == QLatin1Char('v') && c[1] == QLatin1Char('o')
191 && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('d'))
192 return QmlJSGrammar::T_VOID;
193 else if (c[0] == QLatin1Char('w') && c[1] == QLatin1Char('i')
194 && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('h'))
195 return QmlJSGrammar::T_WITH;
196 else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('r')
197 && c[2] == QLatin1Char('u') && c[3] == QLatin1Char('e'))
198 return QmlJSGrammar::T_TRUE;
199 else if (c[0] == QLatin1Char('n') && c[1] == QLatin1Char('u')
200 && c[2] == QLatin1Char('l') && c[3] == QLatin1Char('l'))
201 return QmlJSGrammar::T_NULL;
202 else if (check_reserved) {
203 if (c[0] == QLatin1Char('e') && c[1] == QLatin1Char('n')
204 && c[2] == QLatin1Char('u') && c[3] == QLatin1Char('m'))
205 return QmlJSGrammar::T_RESERVED_WORD;
206 else if (c[0] == QLatin1Char('b') && c[1] == QLatin1Char('y')
207 && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('e'))
208 return QmlJSGrammar::T_RESERVED_WORD;
209 else if (c[0] == QLatin1Char('l') && c[1] == QLatin1Char('o')
210 && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('g'))
211 return QmlJSGrammar::T_RESERVED_WORD;
212 else if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('h')
213 && c[2] == QLatin1Char('a') && c[3] == QLatin1Char('r'))
214 return QmlJSGrammar::T_RESERVED_WORD;
215 else if (c[0] == QLatin1Char('g') && c[1] == QLatin1Char('o')
216 && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('o'))
217 return QmlJSGrammar::T_RESERVED_WORD;
222 if (c[0] == QLatin1Char('b') && c[1] == QLatin1Char('r')
223 && c[2] == QLatin1Char('e') && c[3] == QLatin1Char('a')
224 && c[4] == QLatin1Char('k'))
225 return QmlJSGrammar::T_BREAK;
226 else if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('a')
227 && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('c')
228 && c[4] == QLatin1Char('h'))
229 return QmlJSGrammar::T_CATCH;
230 else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('h')
231 && c[2] == QLatin1Char('r') && c[3] == QLatin1Char('o')
232 && c[4] == QLatin1Char('w'))
233 return QmlJSGrammar::T_THROW;
234 else if (c[0] == QLatin1Char('w') && c[1] == QLatin1Char('h')
235 && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('l')
236 && c[4] == QLatin1Char('e'))
237 return QmlJSGrammar::T_WHILE;
238 else if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('o')
239 && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('s')
240 && c[4] == QLatin1Char('t'))
241 return QmlJSGrammar::T_CONST;
242 else if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('a')
243 && c[2] == QLatin1Char('l') && c[3] == QLatin1Char('s')
244 && c[4] == QLatin1Char('e'))
245 return QmlJSGrammar::T_FALSE;
246 else if (check_reserved) {
247 if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('h')
248 && c[2] == QLatin1Char('o') && c[3] == QLatin1Char('r')
249 && c[4] == QLatin1Char('t'))
250 return QmlJSGrammar::T_RESERVED_WORD;
251 else if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('u')
252 && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('e')
253 && c[4] == QLatin1Char('r'))
254 return QmlJSGrammar::T_RESERVED_WORD;
255 else if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('i')
256 && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('a')
257 && c[4] == QLatin1Char('l'))
258 return QmlJSGrammar::T_RESERVED_WORD;
259 else if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('l')
260 && c[2] == QLatin1Char('a') && c[3] == QLatin1Char('s')
261 && c[4] == QLatin1Char('s'))
262 return QmlJSGrammar::T_RESERVED_WORD;
263 else if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('l')
264 && c[2] == QLatin1Char('o') && c[3] == QLatin1Char('a')
265 && c[4] == QLatin1Char('t'))
266 return QmlJSGrammar::T_RESERVED_WORD;
271 if (c[0] == QLatin1Char('d') && c[1] == QLatin1Char('e')
272 && c[2] == QLatin1Char('l') && c[3] == QLatin1Char('e')
273 && c[4] == QLatin1Char('t') && c[5] == QLatin1Char('e'))
274 return QmlJSGrammar::T_DELETE;
275 else if (c[0] == QLatin1Char('r') && c[1] == QLatin1Char('e')
276 && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('u')
277 && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('n'))
278 return QmlJSGrammar::T_RETURN;
279 else if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('w')
280 && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('t')
281 && c[4] == QLatin1Char('c') && c[5] == QLatin1Char('h'))
282 return QmlJSGrammar::T_SWITCH;
283 else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('y')
284 && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('e')
285 && c[4] == QLatin1Char('o') && c[5] == QLatin1Char('f'))
286 return QmlJSGrammar::T_TYPEOF;
287 else if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('m')
288 && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('o')
289 && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('t'))
290 return QmlJSGrammar::T_IMPORT;
291 else if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('i')
292 && c[2] == QLatin1Char('g') && c[3] == QLatin1Char('n')
293 && c[4] == QLatin1Char('a') && c[5] == QLatin1Char('l'))
294 return QmlJSGrammar::T_SIGNAL;
295 else if (check_reserved) {
296 if (c[0] == QLatin1Char('e') && c[1] == QLatin1Char('x')
297 && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('o')
298 && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('t'))
299 return QmlJSGrammar::T_RESERVED_WORD;
300 else if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('t')
301 && c[2] == QLatin1Char('a') && c[3] == QLatin1Char('t')
302 && c[4] == QLatin1Char('i') && c[5] == QLatin1Char('c'))
303 return QmlJSGrammar::T_RESERVED_WORD;
304 else if (c[0] == QLatin1Char('d') && c[1] == QLatin1Char('o')
305 && c[2] == QLatin1Char('u') && c[3] == QLatin1Char('b')
306 && c[4] == QLatin1Char('l') && c[5] == QLatin1Char('e'))
307 return QmlJSGrammar::T_RESERVED_WORD;
308 else if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('m')
309 && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('o')
310 && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('t'))
311 return QmlJSGrammar::T_RESERVED_WORD;
312 else if (c[0] == QLatin1Char('p') && c[1] == QLatin1Char('u')
313 && c[2] == QLatin1Char('b') && c[3] == QLatin1Char('l')
314 && c[4] == QLatin1Char('i') && c[5] == QLatin1Char('c'))
315 return QmlJSGrammar::T_PUBLIC;
316 else if (c[0] == QLatin1Char('n') && c[1] == QLatin1Char('a')
317 && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('i')
318 && c[4] == QLatin1Char('v') && c[5] == QLatin1Char('e'))
319 return QmlJSGrammar::T_RESERVED_WORD;
320 else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('h')
321 && c[2] == QLatin1Char('r') && c[3] == QLatin1Char('o')
322 && c[4] == QLatin1Char('w') && c[5] == QLatin1Char('s'))
323 return QmlJSGrammar::T_RESERVED_WORD;
328 if (c[0] == QLatin1Char('d') && c[1] == QLatin1Char('e')
329 && c[2] == QLatin1Char('f') && c[3] == QLatin1Char('a')
330 && c[4] == QLatin1Char('u') && c[5] == QLatin1Char('l')
331 && c[6] == QLatin1Char('t'))
332 return QmlJSGrammar::T_DEFAULT;
333 else if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('i')
334 && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('a')
335 && c[4] == QLatin1Char('l') && c[5] == QLatin1Char('l')
336 && c[6] == QLatin1Char('y'))
337 return QmlJSGrammar::T_FINALLY;
338 else if (check_reserved) {
339 if (c[0] == QLatin1Char('b') && c[1] == QLatin1Char('o')
340 && c[2] == QLatin1Char('o') && c[3] == QLatin1Char('l')
341 && c[4] == QLatin1Char('e') && c[5] == QLatin1Char('a')
342 && c[6] == QLatin1Char('n'))
343 return QmlJSGrammar::T_RESERVED_WORD;
344 else if (c[0] == QLatin1Char('e') && c[1] == QLatin1Char('x')
345 && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('e')
346 && c[4] == QLatin1Char('n') && c[5] == QLatin1Char('d')
347 && c[6] == QLatin1Char('s'))
348 return QmlJSGrammar::T_RESERVED_WORD;
349 else if (c[0] == QLatin1Char('p') && c[1] == QLatin1Char('a')
350 && c[2] == QLatin1Char('c') && c[3] == QLatin1Char('k')
351 && c[4] == QLatin1Char('a') && c[5] == QLatin1Char('g')
352 && c[6] == QLatin1Char('e'))
353 return QmlJSGrammar::T_RESERVED_WORD;
354 else if (c[0] == QLatin1Char('p') && c[1] == QLatin1Char('r')
355 && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('v')
356 && c[4] == QLatin1Char('a') && c[5] == QLatin1Char('t')
357 && c[6] == QLatin1Char('e'))
358 return QmlJSGrammar::T_RESERVED_WORD;
363 if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('o')
364 && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('t')
365 && c[4] == QLatin1Char('i') && c[5] == QLatin1Char('n')
366 && c[6] == QLatin1Char('u') && c[7] == QLatin1Char('e'))
367 return QmlJSGrammar::T_CONTINUE;
368 else if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('u')
369 && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('c')
370 && c[4] == QLatin1Char('t') && c[5] == QLatin1Char('i')
371 && c[6] == QLatin1Char('o') && c[7] == QLatin1Char('n'))
372 return QmlJSGrammar::T_FUNCTION;
373 else if (c[0] == QLatin1Char('d') && c[1] == QLatin1Char('e')
374 && c[2] == QLatin1Char('b') && c[3] == QLatin1Char('u')
375 && c[4] == QLatin1Char('g') && c[5] == QLatin1Char('g')
376 && c[6] == QLatin1Char('e') && c[7] == QLatin1Char('r'))
377 return QmlJSGrammar::T_DEBUGGER;
378 else if (c[0] == QLatin1Char('p') && c[1] == QLatin1Char('r')
379 && c[2] == QLatin1Char('o') && c[3] == QLatin1Char('p')
380 && c[4] == QLatin1Char('e') && c[5] == QLatin1Char('r')
381 && c[6] == QLatin1Char('t') && c[7] == QLatin1Char('y'))
382 return QmlJSGrammar::T_PROPERTY;
383 else if (c[0] == QLatin1Char('r') && c[1] == QLatin1Char('e')
384 && c[2] == QLatin1Char('a') && c[3] == QLatin1Char('d')
385 && c[4] == QLatin1Char('o') && c[5] == QLatin1Char('n')
386 && c[6] == QLatin1Char('l') && c[7] == QLatin1Char('y'))
387 return QmlJSGrammar::T_READONLY;
388 else if (check_reserved) {
389 if (c[0] == QLatin1Char('a') && c[1] == QLatin1Char('b')
390 && c[2] == QLatin1Char('s') && c[3] == QLatin1Char('t')
391 && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('a')
392 && c[6] == QLatin1Char('c') && c[7] == QLatin1Char('t'))
393 return QmlJSGrammar::T_RESERVED_WORD;
394 else if (c[0] == QLatin1Char('v') && c[1] == QLatin1Char('o')
395 && c[2] == QLatin1Char('l') && c[3] == QLatin1Char('a')
396 && c[4] == QLatin1Char('t') && c[5] == QLatin1Char('i')
397 && c[6] == QLatin1Char('l') && c[7] == QLatin1Char('e'))
398 return QmlJSGrammar::T_RESERVED_WORD;
403 if (check_reserved) {
404 if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('n')
405 && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('e')
406 && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('f')
407 && c[6] == QLatin1Char('a') && c[7] == QLatin1Char('c')
408 && c[8] == QLatin1Char('e'))
409 return QmlJSGrammar::T_RESERVED_WORD;
410 else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('r')
411 && c[2] == QLatin1Char('a') && c[3] == QLatin1Char('n')
412 && c[4] == QLatin1Char('s') && c[5] == QLatin1Char('i')
413 && c[6] == QLatin1Char('e') && c[7] == QLatin1Char('n')
414 && c[8] == QLatin1Char('t'))
415 return QmlJSGrammar::T_RESERVED_WORD;
416 else if (c[0] == QLatin1Char('p') && c[1] == QLatin1Char('r')
417 && c[2] == QLatin1Char('o') && c[3] == QLatin1Char('t')
418 && c[4] == QLatin1Char('e') && c[5] == QLatin1Char('c')
419 && c[6] == QLatin1Char('t') && c[7] == QLatin1Char('e')
420 && c[8] == QLatin1Char('d'))
421 return QmlJSGrammar::T_RESERVED_WORD;
426 if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('n')
427 && c[2] == QLatin1Char('s') && c[3] == QLatin1Char('t')
428 && c[4] == QLatin1Char('a') && c[5] == QLatin1Char('n')
429 && c[6] == QLatin1Char('c') && c[7] == QLatin1Char('e')
430 && c[8] == QLatin1Char('o') && c[9] == QLatin1Char('f'))
431 return QmlJSGrammar::T_INSTANCEOF;
432 else if (check_reserved) {
433 if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('m')
434 && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('l')
435 && c[4] == QLatin1Char('e') && c[5] == QLatin1Char('m')
436 && c[6] == QLatin1Char('e') && c[7] == QLatin1Char('n')
437 && c[8] == QLatin1Char('t') && c[9] == QLatin1Char('s'))
438 return QmlJSGrammar::T_RESERVED_WORD;
443 if (check_reserved) {
444 if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('y')
445 && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('c')
446 && c[4] == QLatin1Char('h') && c[5] == QLatin1Char('r')
447 && c[6] == QLatin1Char('o') && c[7] == QLatin1Char('n')
448 && c[8] == QLatin1Char('i') && c[9] == QLatin1Char('z')
449 && c[10] == QLatin1Char('e') && c[11] == QLatin1Char('d'))
450 return QmlJSGrammar::T_RESERVED_WORD;
463 ushort stringType = 0; // either single or double quotes
464 bool multiLineString = false;
469 // did we push a token on the stack previously ?
470 // (after an automatic semicolon insertion)
471 if (stackToken >= 0) {
477 bool identifierWithEscapedUnicode = false;
482 if (isWhiteSpace()) {
484 } else if (current == '/' && next1 == '/') {
487 state = InSingleLineComment;
488 } else if (current == '/' && next1 == '*') {
491 state = InMultiLineComment;
492 } else if (current == 0) {
493 syncProhibitAutomaticSemicolon();
494 if (!terminator && !delimited && !prohibitAutomaticSemicolon) {
495 // automatic semicolon insertion if program incomplete
496 token = QmlJSGrammar::T_SEMICOLON;
502 } else if (isLineTerminator()) {
504 // automatic semicolon insertion
506 token = QmlJSGrammar::T_SEMICOLON;
509 shiftWindowsLineBreak();
514 syncProhibitAutomaticSemicolon();
516 } else if (current == '"' || current == '\'') {
519 multiLineString = false;
520 stringType = current;
521 } else if (current == '\\' && next1 == 'u') {
522 identifierWithEscapedUnicode = true;
525 shift(2); // skip the unicode escape prefix `\u'
527 if (isHexDigit(current) && isHexDigit(next1) &&
528 isHexDigit(next2) && isHexDigit(next3)) {
529 record16(convertUnicode(current, next1, next2, next3));
531 state = InIdentifier;
534 err = IllegalUnicodeEscapeSequence;
535 errmsg = QCoreApplication::translate("QmlParser", "Illegal unicode escape sequence");
539 } else if (isIdentLetter(current)) {
540 identifierWithEscapedUnicode = false;
543 state = InIdentifier;
544 } else if (current == '0') {
548 } else if (isDecimalDigit(current)) {
552 } else if (current == '.' && isDecimalDigit(next1)) {
558 token = matchPunctuator(current, next1, next2, next3);
560 if (terminator && !delimited && !prohibitAutomaticSemicolon
561 && (token == QmlJSGrammar::T_PLUS_PLUS
562 || token == QmlJSGrammar::T_MINUS_MINUS)) {
563 // automatic semicolon insertion
565 token = QmlJSGrammar::T_SEMICOLON;
571 err = IllegalCharacter;
572 errmsg = QCoreApplication::translate("QmlParser", "Illegal character");
577 if (current == stringType) {
580 } else if (isLineTerminator()) {
581 multiLineString = true;
583 } else if (current == 0 || isLineTerminator()) {
585 err = UnclosedStringLiteral;
586 errmsg = QCoreApplication::translate("QmlParser", "Unclosed string at end of line");
587 } else if (current == '\\') {
588 state = InEscapeSequence;
593 // Escape Sequences inside of strings
594 case InEscapeSequence:
595 if (isOctalDigit(current)) {
596 if (current >= '0' && current <= '3' &&
597 isOctalDigit(next1) && isOctalDigit(next2)) {
598 record16(convertOctal(current, next1, next2));
601 } else if (isOctalDigit(current) &&
602 isOctalDigit(next1)) {
603 record16(convertOctal('0', current, next1));
606 } else if (isOctalDigit(current)) {
607 record16(convertOctal('0', '0', current));
611 err = IllegalEscapeSequence;
612 errmsg = QCoreApplication::translate("QmlParser", "Illegal escape sequence");
614 } else if (current == 'x')
616 else if (current == 'u')
617 state = InUnicodeEscape;
619 if (isLineTerminator()) {
620 shiftWindowsLineBreak();
625 record16(singleEscape(current));
631 if (isHexDigit(current) && isHexDigit(next1)) {
633 record16(QLatin1Char(convertHex(current, next1)));
635 } else if (current == stringType) {
636 record16(QLatin1Char('x'));
640 record16(QLatin1Char('x'));
645 case InUnicodeEscape:
646 if (isHexDigit(current) && isHexDigit(next1) &&
647 isHexDigit(next2) && isHexDigit(next3)) {
648 record16(convertUnicode(current, next1, next2, next3));
651 } else if (current == stringType) {
652 record16(QLatin1Char('u'));
657 err = IllegalUnicodeEscapeSequence;
658 errmsg = QCoreApplication::translate("QmlParser", "Illegal unicode escape sequence");
661 case InSingleLineComment:
662 if (isLineTerminator()) {
663 shiftWindowsLineBreak();
669 token = QmlJSGrammar::T_SEMICOLON;
673 if (driver) driver->addComment(startpos+2, tokenLength()-2, startlineno, startcolumn+2);
674 } else if (current == 0) {
675 if (driver) driver->addComment(startpos+2, tokenLength()-2, startlineno, startcolumn+2);
680 case InMultiLineComment:
683 err = UnclosedComment;
684 errmsg = QCoreApplication::translate("QmlParser", "Unclosed comment at end of file");
685 if (driver) driver->addComment(startpos+2, tokenLength()-2, startlineno, startcolumn+2);
686 } else if (isLineTerminator()) {
687 shiftWindowsLineBreak();
689 } else if (current == '*' && next1 == '/') {
692 if (driver) driver->addComment(startpos+2, tokenLength()-3, startlineno, startcolumn+2);
697 if (isIdentLetter(current) || isDecimalDigit(current)) {
700 } else if (current == '\\' && next1 == 'u') {
701 identifierWithEscapedUnicode = true;
702 shift(2); // skip the unicode escape prefix `\u'
704 if (isHexDigit(current) && isHexDigit(next1) &&
705 isHexDigit(next2) && isHexDigit(next3)) {
706 record16(convertUnicode(current, next1, next2, next3));
711 err = IllegalUnicodeEscapeSequence;
712 errmsg = QCoreApplication::translate("QmlParser", "Illegal unicode escape sequence");
719 if (current == 'x' || current == 'X') {
722 } else if (current == '.') {
725 } else if (current == 'e' || current == 'E') {
727 state = InExponentIndicator;
728 } else if (isOctalDigit(current)) {
731 } else if (isDecimalDigit(current)) {
739 if (isHexDigit(current))
745 if (isOctalDigit(current)) {
747 } else if (isDecimalDigit(current)) {
755 if (isDecimalDigit(current)) {
757 } else if (current == '.') {
760 } else if (current == 'e' || current == 'E') {
762 state = InExponentIndicator;
768 if (isDecimalDigit(current)) {
770 } else if (current == 'e' || current == 'E') {
772 state = InExponentIndicator;
777 case InExponentIndicator:
778 if (current == '+' || current == '-') {
780 } else if (isDecimalDigit(current)) {
785 err = IllegalExponentIndicator;
786 errmsg = QCoreApplication::translate("QmlParser", "Illegal syntax for exponential number");
790 if (isDecimalDigit(current)) {
797 Q_ASSERT_X(0, "Lexer::lex", "Unhandled state in switch statement");
800 // move on to the next character
803 if (state != Start && state != InSingleLineComment)
807 // no identifiers allowed directly after numeric literal, e.g. "3in" is bad
808 if ((state == Number || state == Octal || state == Hex)
809 && isIdentLetter(current)) {
811 err = IllegalIdentifier;
812 errmsg = QCoreApplication::translate("QmlParser", "Identifier cannot start with numeric literal");
816 buffer8[pos8] = '\0';
819 if (state == Number) {
820 dval = qstrtod(buffer8, 0, 0);
821 } else if (state == Hex) { // scan hex numbers
822 dval = integerFromString(buffer8, pos8, 16);
824 } else if (state == Octal) { // scan octal number
825 dval = integerFromString(buffer8, pos8, 8);
829 restrKeyword = false;
832 switch (parenthesesState) {
833 case IgnoreParentheses:
835 case CountParentheses:
836 if (token == QmlJSGrammar::T_RPAREN) {
838 if (parenthesesCount == 0)
839 parenthesesState = BalancedParentheses;
840 } else if (token == QmlJSGrammar::T_LPAREN) {
844 case BalancedParentheses:
845 parenthesesState = IgnoreParentheses;
853 if (token == QmlJSGrammar::T_RBRACE || token == QmlJSGrammar::T_SEMICOLON)
858 if (! identifierWithEscapedUnicode)
859 token = findReservedWord(buffer16, pos16);
862 /* TODO: close leak on parse error. same holds true for String */
864 qsyylval.ustr = driver->intern(buffer16, pos16);
867 return QmlJSGrammar::T_IDENTIFIER;
869 if (token == QmlJSGrammar::T_CONTINUE || token == QmlJSGrammar::T_BREAK
870 || token == QmlJSGrammar::T_RETURN || token == QmlJSGrammar::T_THROW) {
872 } else if (token == QmlJSGrammar::T_IF || token == QmlJSGrammar::T_FOR
873 || token == QmlJSGrammar::T_WHILE || token == QmlJSGrammar::T_WITH) {
874 parenthesesState = CountParentheses;
875 parenthesesCount = 0;
876 } else if (token == QmlJSGrammar::T_DO) {
877 parenthesesState = BalancedParentheses;
882 qsyylval.ustr = driver->intern(buffer16, pos16);
885 return multiLineString?QmlJSGrammar::T_MULTILINE_STRING_LITERAL:QmlJSGrammar::T_STRING_LITERAL;
887 qsyylval.dval = dval;
888 return QmlJSGrammar::T_NUMERIC_LITERAL;
892 Q_ASSERT(!"unhandled numeration value in switch");
897 bool Lexer::isWhiteSpace() const
899 return (current == ' ' || current == '\t' ||
900 current == 0x0b || current == 0x0c);
903 bool Lexer::isLineTerminator() const
905 return (current == '\n' || current == '\r');
908 bool Lexer::isIdentLetter(ushort c)
910 // ASCII-biased, since all reserved words are ASCII, aand hence the
911 // bulk of content to be parsed.
912 if ((c >= 'a' && c <= 'z')
913 || (c >= 'A' && c <= 'Z')
919 return QChar(c).isLetterOrNumber();
922 bool Lexer::isDecimalDigit(ushort c)
924 return (c >= '0' && c <= '9');
927 bool Lexer::isHexDigit(ushort c) const
929 return ((c >= '0' && c <= '9')
930 || (c >= 'a' && c <= 'f')
931 || (c >= 'A' && c <= 'F'));
934 bool Lexer::isOctalDigit(ushort c) const
936 return (c >= '0' && c <= '7');
939 int Lexer::matchPunctuator(ushort c1, ushort c2,
940 ushort c3, ushort c4)
942 if (c1 == '>' && c2 == '>' && c3 == '>' && c4 == '=') {
944 return QmlJSGrammar::T_GT_GT_GT_EQ;
945 } else if (c1 == '=' && c2 == '=' && c3 == '=') {
947 return QmlJSGrammar::T_EQ_EQ_EQ;
948 } else if (c1 == '!' && c2 == '=' && c3 == '=') {
950 return QmlJSGrammar::T_NOT_EQ_EQ;
951 } else if (c1 == '>' && c2 == '>' && c3 == '>') {
953 return QmlJSGrammar::T_GT_GT_GT;
954 } else if (c1 == '<' && c2 == '<' && c3 == '=') {
956 return QmlJSGrammar::T_LT_LT_EQ;
957 } else if (c1 == '>' && c2 == '>' && c3 == '=') {
959 return QmlJSGrammar::T_GT_GT_EQ;
960 } else if (c1 == '<' && c2 == '=') {
962 return QmlJSGrammar::T_LE;
963 } else if (c1 == '>' && c2 == '=') {
965 return QmlJSGrammar::T_GE;
966 } else if (c1 == '!' && c2 == '=') {
968 return QmlJSGrammar::T_NOT_EQ;
969 } else if (c1 == '+' && c2 == '+') {
971 return QmlJSGrammar::T_PLUS_PLUS;
972 } else if (c1 == '-' && c2 == '-') {
974 return QmlJSGrammar::T_MINUS_MINUS;
975 } else if (c1 == '=' && c2 == '=') {
977 return QmlJSGrammar::T_EQ_EQ;
978 } else if (c1 == '+' && c2 == '=') {
980 return QmlJSGrammar::T_PLUS_EQ;
981 } else if (c1 == '-' && c2 == '=') {
983 return QmlJSGrammar::T_MINUS_EQ;
984 } else if (c1 == '*' && c2 == '=') {
986 return QmlJSGrammar::T_STAR_EQ;
987 } else if (c1 == '/' && c2 == '=') {
989 return QmlJSGrammar::T_DIVIDE_EQ;
990 } else if (c1 == '&' && c2 == '=') {
992 return QmlJSGrammar::T_AND_EQ;
993 } else if (c1 == '^' && c2 == '=') {
995 return QmlJSGrammar::T_XOR_EQ;
996 } else if (c1 == '%' && c2 == '=') {
998 return QmlJSGrammar::T_REMAINDER_EQ;
999 } else if (c1 == '|' && c2 == '=') {
1001 return QmlJSGrammar::T_OR_EQ;
1002 } else if (c1 == '<' && c2 == '<') {
1004 return QmlJSGrammar::T_LT_LT;
1005 } else if (c1 == '>' && c2 == '>') {
1007 return QmlJSGrammar::T_GT_GT;
1008 } else if (c1 == '&' && c2 == '&') {
1010 return QmlJSGrammar::T_AND_AND;
1011 } else if (c1 == '|' && c2 == '|') {
1013 return QmlJSGrammar::T_OR_OR;
1017 case '=': shift(1); return QmlJSGrammar::T_EQ;
1018 case '>': shift(1); return QmlJSGrammar::T_GT;
1019 case '<': shift(1); return QmlJSGrammar::T_LT;
1020 case ',': shift(1); return QmlJSGrammar::T_COMMA;
1021 case '!': shift(1); return QmlJSGrammar::T_NOT;
1022 case '~': shift(1); return QmlJSGrammar::T_TILDE;
1023 case '?': shift(1); return QmlJSGrammar::T_QUESTION;
1024 case ':': shift(1); return QmlJSGrammar::T_COLON;
1025 case '.': shift(1); return QmlJSGrammar::T_DOT;
1026 case '+': shift(1); return QmlJSGrammar::T_PLUS;
1027 case '-': shift(1); return QmlJSGrammar::T_MINUS;
1028 case '*': shift(1); return QmlJSGrammar::T_STAR;
1029 case '/': shift(1); return QmlJSGrammar::T_DIVIDE_;
1030 case '&': shift(1); return QmlJSGrammar::T_AND;
1031 case '|': shift(1); return QmlJSGrammar::T_OR;
1032 case '^': shift(1); return QmlJSGrammar::T_XOR;
1033 case '%': shift(1); return QmlJSGrammar::T_REMAINDER;
1034 case '(': shift(1); return QmlJSGrammar::T_LPAREN;
1035 case ')': shift(1); return QmlJSGrammar::T_RPAREN;
1036 case '{': shift(1); return QmlJSGrammar::T_LBRACE;
1037 case '}': shift(1); return QmlJSGrammar::T_RBRACE;
1038 case '[': shift(1); return QmlJSGrammar::T_LBRACKET;
1039 case ']': shift(1); return QmlJSGrammar::T_RBRACKET;
1040 case ';': shift(1); return QmlJSGrammar::T_SEMICOLON;
1046 ushort Lexer::singleEscape(ushort c) const
1072 ushort Lexer::convertOctal(ushort c1, ushort c2,
1075 return ((c1 - '0') * 64 + (c2 - '0') * 8 + c3 - '0');
1078 unsigned char Lexer::convertHex(ushort c)
1080 if (c >= '0' && c <= '9')
1082 else if (c >= 'a' && c <= 'f')
1083 return (c - 'a' + 10);
1085 return (c - 'A' + 10);
1088 unsigned char Lexer::convertHex(ushort c1, ushort c2)
1090 return ((convertHex(c1) << 4) + convertHex(c2));
1093 QChar Lexer::convertUnicode(ushort c1, ushort c2,
1094 ushort c3, ushort c4)
1096 return QChar((convertHex(c3) << 4) + convertHex(c4),
1097 (convertHex(c1) << 4) + convertHex(c2));
1100 void Lexer::record8(ushort c)
1102 Q_ASSERT(c <= 0xff);
1104 // enlarge buffer if full
1105 if (pos8 >= size8 - 1) {
1106 char *tmp = new char[2 * size8];
1107 memcpy(tmp, buffer8, size8 * sizeof(char));
1113 buffer8[pos8++] = (char) c;
1116 void Lexer::record16(QChar c)
1118 // enlarge buffer if full
1119 if (pos16 >= size16 - 1) {
1120 QChar *tmp = new QChar[2 * size16];
1121 memcpy(tmp, buffer16, size16 * sizeof(QChar));
1127 buffer16[pos16++] = c;
1130 void Lexer::recordStartPos()
1133 startlineno = yylineno;
1134 startcolumn = yycolumn;
1137 bool Lexer::scanRegExp(RegExpBodyPrefix prefix)
1142 if (prefix == EqualPrefix)
1143 record16(QLatin1Char('='));
1149 case '\n': case '\r': // line terminator
1150 errmsg = QCoreApplication::translate("QmlParser", "Unterminated regular expression literal");
1156 if (driver) // create the pattern
1157 pattern = driver->intern(buffer16, pos16);
1162 while (isIdentLetter(current)) {
1163 int flag = Ecma::RegExp::flagFromChar(current);
1165 errmsg = QCoreApplication::translate("QmlParser", "Invalid regular expression flag '%0'")
1166 .arg(QChar(current));
1176 // regular expression backslash sequence
1180 if (! current || isLineTerminator()) {
1181 errmsg = QCoreApplication::translate("QmlParser", "Unterminated regular expression backslash sequence");
1190 // regular expression class
1194 while (current && ! isLineTerminator()) {
1197 else if (current == '\\') {
1198 // regular expression backslash sequence
1202 if (! current || isLineTerminator()) {
1203 errmsg = QCoreApplication::translate("QmlParser", "Unterminated regular expression backslash sequence");
1215 if (current != ']') {
1216 errmsg = QCoreApplication::translate("QmlParser", "Unterminated regular expression class");
1233 void Lexer::syncProhibitAutomaticSemicolon()
1235 if (parenthesesState == BalancedParentheses) {
1236 // we have seen something like "if (foo)", which means we should
1237 // never insert an automatic semicolon at this point, since it would
1238 // then be expanded into an empty statement (ECMA-262 7.9.1)
1239 prohibitAutomaticSemicolon = true;
1240 parenthesesState = IgnoreParentheses;
1242 prohibitAutomaticSemicolon = false;
1246 QT_QML_END_NAMESPACE