OSDN Git Service

Update license.
[qt-creator-jp/qt-creator-jp.git] / src / libs / qmljs / parser / qmljslexer.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (info@qt.nokia.com)
8 **
9 ** GNU Lesser General Public License Usage
10 **
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.
17 **
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.
21 **
22 ** Other Usage
23 **
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.
26 **
27 ** If you have questions regarding the use of this file, please contact
28 ** Nokia at qt-info@nokia.com.
29 **
30 **************************************************************************/
31
32 #ifdef HAVE_CONFIG_H
33 #include <config.h>
34 #endif
35
36 #include "qmljslexer_p.h"
37
38 #include "qmljsglobal_p.h"
39 #include "qmljsengine_p.h"
40 #include "qmljsgrammar_p.h"
41
42 #include <QtCore/qcoreapplication.h>
43
44 #include <ctype.h>
45 #include <stdlib.h>
46 #include <stdio.h>
47 #include <string.h>
48
49 QT_BEGIN_NAMESPACE
50 Q_CORE_EXPORT double qstrtod(const char *s00, char const **se, bool *ok);
51 QT_END_NAMESPACE
52
53 QT_QML_BEGIN_NAMESPACE
54
55 #define shiftWindowsLineBreak() \
56     do { \
57         if (((current == '\r') && (next1 == '\n')) \
58             || ((current == '\n') && (next1 == '\r'))) { \
59             shift(1); \
60         } \
61     } \
62     while (0)
63
64 namespace QmlJS {
65 extern double integerFromString(const char *buf, int size, int radix);
66 }
67
68 using namespace QmlJS;
69
70 Lexer::Lexer(Engine *eng, bool tokenizeComments)
71     : driver(eng),
72       yylineno(0),
73       done(false),
74       size8(128), size16(128),
75       pos8(0), pos16(0),
76       terminator(false),
77       restrKeyword(false),
78       delimited(false),
79       stackToken(-1),
80       state(Start),
81       pos(0),
82       code(0), length(0),
83       yycolumn(0),
84       startpos(0),
85       startlineno(0), startcolumn(0),
86       bol(true),
87       current(0), next1(0), next2(0), next3(0),
88       err(NoError),
89       wantRx(false),
90       check_reserved(true),
91       parenthesesState(IgnoreParentheses),
92       parenthesesCount(0),
93       prohibitAutomaticSemicolon(false),
94       tokenizeComments(tokenizeComments)
95 {
96     if (driver) driver->setLexer(this);
97     // allocate space for read buffers
98     buffer8 = new char[size8];
99     buffer16 = new QChar[size16];
100     pattern = 0;
101     flags = 0;
102
103 }
104
105 Lexer::~Lexer()
106 {
107     delete [] buffer8;
108     delete [] buffer16;
109 }
110
111 void Lexer::setCode(const QString &c, int lineno)
112 {
113     errmsg.clear();
114     yylineno = lineno;
115     yycolumn = 1;
116     restrKeyword = false;
117     delimited = false;
118     stackToken = -1;
119     pos = 0;
120     code = c.unicode();
121     length = c.length();
122     bol = true;
123
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;
129 }
130
131 void Lexer::shift(uint p)
132 {
133     while (p--) {
134         ++pos;
135         ++yycolumn;
136         current = next1;
137         next1 = next2;
138         next2 = next3;
139         next3 = (pos + 3 < length) ? code[pos+3].unicode() : 0;
140     }
141 }
142
143 void Lexer::setDone(State s)
144 {
145     state = s;
146     done = true;
147 }
148
149 int Lexer::findReservedWord(const QChar *c, int size) const
150 {
151     switch (size) {
152     case 2: {
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;
163     }   break;
164
165     case 3: {
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;
177         }
178     }   break;
179
180     case 4: {
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;
218         }
219     }   break;
220
221     case 5: {
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;
267         }
268     }   break;
269
270     case 6: {
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;
324         }
325     }   break;
326
327     case 7: {
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;
359         }
360     }   break;
361
362     case 8: {
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;
399         }
400     }   break;
401
402     case 9: {
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;
422         }
423     }   break;
424
425     case 10: {
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;
439         }
440     }   break;
441
442     case 12: {
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;
451         }
452     }   break;
453
454     } // switch
455
456     return -1;
457 }
458
459 int Lexer::lex()
460 {
461     int token = 0;
462     state = Start;
463     ushort stringType = 0; // either single or double quotes
464     bool multiLineString = false;
465     pos8 = pos16 = 0;
466     done = false;
467     terminator = false;
468
469     // did we push a token on the stack previously ?
470     // (after an automatic semicolon insertion)
471     if (stackToken >= 0) {
472         setDone(Other);
473         token = stackToken;
474         stackToken = -1;
475     }
476
477     bool identifierWithEscapedUnicode = false;
478
479     while (!done) {
480         switch (state) {
481         case Start:
482             if (isWhiteSpace()) {
483                 // do nothing
484             } else if (current == '/' && next1 == '/') {
485                 recordStartPos();
486                 shift(1);
487                 state = InSingleLineComment;
488             } else if (current == '/' && next1 == '*') {
489                 recordStartPos();
490                 shift(1);
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;
497                     stackToken = 0;
498                     setDone(Other);
499                 } else {
500                     setDone(Eof);
501                 }
502             } else if (isLineTerminator()) {
503                 if (restrKeyword) {
504                     // automatic semicolon insertion
505                     recordStartPos();
506                     token = QmlJSGrammar::T_SEMICOLON;
507                     setDone(Other);
508                 } else {
509                     shiftWindowsLineBreak();
510                     yylineno++;
511                     yycolumn = 0;
512                     bol = true;
513                     terminator = true;
514                     syncProhibitAutomaticSemicolon();
515                 }
516             } else if (current == '"' || current == '\'') {
517                 recordStartPos();
518                 state = InString;
519                 multiLineString = false;
520                 stringType = current;
521             } else if (current == '\\' && next1 == 'u') {
522                 identifierWithEscapedUnicode = true;
523                 recordStartPos();
524
525                 shift(2); // skip the unicode escape prefix `\u'
526
527                 if (isHexDigit(current) && isHexDigit(next1) &&
528                      isHexDigit(next2) && isHexDigit(next3)) {
529                     record16(convertUnicode(current, next1, next2, next3));
530                     shift(3);
531                     state = InIdentifier;
532                 } else {
533                     setDone(Bad);
534                     err = IllegalUnicodeEscapeSequence;
535                     errmsg = QCoreApplication::translate("QmlParser", "Illegal unicode escape sequence");
536                     break;
537                 }
538
539             } else if (isIdentLetter(current)) {
540                 identifierWithEscapedUnicode = false;
541                 recordStartPos();
542                 record16(current);
543                 state = InIdentifier;
544             } else if (current == '0') {
545                 recordStartPos();
546                 record8(current);
547                 state = InNum0;
548             } else if (isDecimalDigit(current)) {
549                 recordStartPos();
550                 record8(current);
551                 state = InNum;
552             } else if (current == '.' && isDecimalDigit(next1)) {
553                 recordStartPos();
554                 record8(current);
555                 state = InDecimal;
556             } else {
557                 recordStartPos();
558                 token = matchPunctuator(current, next1, next2, next3);
559                 if (token != -1) {
560                     if (terminator && !delimited && !prohibitAutomaticSemicolon
561                         && (token == QmlJSGrammar::T_PLUS_PLUS
562                             || token == QmlJSGrammar::T_MINUS_MINUS)) {
563                         // automatic semicolon insertion
564                         stackToken = token;
565                         token = QmlJSGrammar::T_SEMICOLON;
566                     }
567                     setDone(Other);
568                 }
569                 else {
570                     setDone(Bad);
571                     err = IllegalCharacter;
572                     errmsg = QCoreApplication::translate("QmlParser", "Illegal character");
573                 }
574             }
575             break;
576         case InString:
577             if (current == stringType) {
578                 shift(1);
579                 setDone(String);
580             } else if (isLineTerminator()) {
581                 multiLineString = true;
582                 record16(current);
583             } else if (current == 0 || isLineTerminator()) {
584                 setDone(Bad);
585                 err = UnclosedStringLiteral;
586                 errmsg = QCoreApplication::translate("QmlParser", "Unclosed string at end of line");
587             } else if (current == '\\') {
588                 state = InEscapeSequence;
589             } else {
590                 record16(current);
591             }
592             break;
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));
599                     shift(2);
600                     state = InString;
601                 } else if (isOctalDigit(current) &&
602                             isOctalDigit(next1)) {
603                     record16(convertOctal('0', current, next1));
604                     shift(1);
605                     state = InString;
606                 } else if (isOctalDigit(current)) {
607                     record16(convertOctal('0', '0', current));
608                     state = InString;
609                 } else {
610                     setDone(Bad);
611                     err = IllegalEscapeSequence;
612                     errmsg = QCoreApplication::translate("QmlParser", "Illegal escape sequence");
613                 }
614             } else if (current == 'x')
615                 state = InHexEscape;
616             else if (current == 'u')
617                 state = InUnicodeEscape;
618             else {
619                 if (isLineTerminator()) {
620                     shiftWindowsLineBreak();
621                     yylineno++;
622                     yycolumn = 0;
623                     bol = true;
624                 } else {
625                     record16(singleEscape(current));
626                 }
627                 state = InString;
628             }
629             break;
630         case InHexEscape:
631             if (isHexDigit(current) && isHexDigit(next1)) {
632                 state = InString;
633                 record16(QLatin1Char(convertHex(current, next1)));
634                 shift(1);
635             } else if (current == stringType) {
636                 record16(QLatin1Char('x'));
637                 shift(1);
638                 setDone(String);
639             } else {
640                 record16(QLatin1Char('x'));
641                 record16(current);
642                 state = InString;
643             }
644             break;
645         case InUnicodeEscape:
646             if (isHexDigit(current) && isHexDigit(next1) &&
647                  isHexDigit(next2) && isHexDigit(next3)) {
648                 record16(convertUnicode(current, next1, next2, next3));
649                 shift(3);
650                 state = InString;
651             } else if (current == stringType) {
652                 record16(QLatin1Char('u'));
653                 shift(1);
654                 setDone(String);
655             } else {
656                 setDone(Bad);
657                 err = IllegalUnicodeEscapeSequence;
658                 errmsg = QCoreApplication::translate("QmlParser", "Illegal unicode escape sequence");
659             }
660             break;
661         case InSingleLineComment:
662             if (isLineTerminator()) {
663                 shiftWindowsLineBreak();
664                 yylineno++;
665                 yycolumn = 0;
666                 terminator = true;
667                 bol = true;
668                 if (restrKeyword) {
669                     token = QmlJSGrammar::T_SEMICOLON;
670                     setDone(Other);
671                 } else
672                     state = Start;
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);
676                 setDone(Eof);
677             }
678
679             break;
680         case InMultiLineComment:
681             if (current == 0) {
682                 setDone(Bad);
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();
688                 yylineno++;
689             } else if (current == '*' && next1 == '/') {
690                 state = Start;
691                 shift(1);
692                 if (driver) driver->addComment(startpos+2, tokenLength()-3, startlineno, startcolumn+2);
693             }
694
695             break;
696         case InIdentifier:
697             if (isIdentLetter(current) || isDecimalDigit(current)) {
698                 record16(current);
699                 break;
700             } else if (current == '\\' && next1 == 'u') {
701                 identifierWithEscapedUnicode = true;
702                 shift(2); // skip the unicode escape prefix `\u'
703
704                 if (isHexDigit(current) && isHexDigit(next1) &&
705                      isHexDigit(next2) && isHexDigit(next3)) {
706                     record16(convertUnicode(current, next1, next2, next3));
707                     shift(3);
708                     break;
709                 } else {
710                     setDone(Bad);
711                     err = IllegalUnicodeEscapeSequence;
712                     errmsg = QCoreApplication::translate("QmlParser", "Illegal unicode escape sequence");
713                     break;
714                 }
715             }
716             setDone(Identifier);
717             break;
718         case InNum0:
719             if (current == 'x' || current == 'X') {
720                 record8(current);
721                 state = InHex;
722             } else if (current == '.') {
723                 record8(current);
724                 state = InDecimal;
725             } else if (current == 'e' || current == 'E') {
726                 record8(current);
727                 state = InExponentIndicator;
728             } else if (isOctalDigit(current)) {
729                 record8(current);
730                 state = InOctal;
731             } else if (isDecimalDigit(current)) {
732                 record8(current);
733                 state = InDecimal;
734             } else {
735                 setDone(Number);
736             }
737             break;
738         case InHex:
739             if (isHexDigit(current))
740                 record8(current);
741             else
742                 setDone(Hex);
743             break;
744         case InOctal:
745             if (isOctalDigit(current)) {
746                 record8(current);
747             } else if (isDecimalDigit(current)) {
748                 record8(current);
749                 state = InDecimal;
750             } else {
751                 setDone(Octal);
752             }
753             break;
754         case InNum:
755             if (isDecimalDigit(current)) {
756                 record8(current);
757             } else if (current == '.') {
758                 record8(current);
759                 state = InDecimal;
760             } else if (current == 'e' || current == 'E') {
761                 record8(current);
762                 state = InExponentIndicator;
763             } else {
764                 setDone(Number);
765             }
766             break;
767         case InDecimal:
768             if (isDecimalDigit(current)) {
769                 record8(current);
770             } else if (current == 'e' || current == 'E') {
771                 record8(current);
772                 state = InExponentIndicator;
773             } else {
774                 setDone(Number);
775             }
776             break;
777         case InExponentIndicator:
778             if (current == '+' || current == '-') {
779                 record8(current);
780             } else if (isDecimalDigit(current)) {
781                 record8(current);
782                 state = InExponent;
783             } else {
784                 setDone(Bad);
785                 err = IllegalExponentIndicator;
786                 errmsg = QCoreApplication::translate("QmlParser", "Illegal syntax for exponential number");
787             }
788             break;
789         case InExponent:
790             if (isDecimalDigit(current)) {
791                 record8(current);
792             } else {
793                 setDone(Number);
794             }
795             break;
796         default:
797             Q_ASSERT_X(0, "Lexer::lex", "Unhandled state in switch statement");
798         }
799
800         // move on to the next character
801         if (!done)
802             shift(1);
803         if (state != Start && state != InSingleLineComment)
804             bol = false;
805     }
806
807     // no identifiers allowed directly after numeric literal, e.g. "3in" is bad
808     if ((state == Number || state == Octal || state == Hex)
809          && isIdentLetter(current)) {
810         state = Bad;
811         err = IllegalIdentifier;
812         errmsg = QCoreApplication::translate("QmlParser", "Identifier cannot start with numeric literal");
813     }
814
815     // terminate string
816     buffer8[pos8] = '\0';
817
818     double dval = 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);
823         state = Number;
824     } else if (state == Octal) {   // scan octal number
825         dval = integerFromString(buffer8, pos8, 8);
826         state = Number;
827     }
828
829     restrKeyword = false;
830     delimited = false;
831
832     switch (parenthesesState) {
833     case IgnoreParentheses:
834         break;
835     case CountParentheses:
836         if (token == QmlJSGrammar::T_RPAREN) {
837             --parenthesesCount;
838             if (parenthesesCount == 0)
839                 parenthesesState = BalancedParentheses;
840         } else if (token == QmlJSGrammar::T_LPAREN) {
841             ++parenthesesCount;
842         }
843         break;
844     case BalancedParentheses:
845         parenthesesState = IgnoreParentheses;
846         break;
847     }
848
849     switch (state) {
850     case Eof:
851         return 0;
852     case Other:
853         if (token == QmlJSGrammar::T_RBRACE || token == QmlJSGrammar::T_SEMICOLON)
854             delimited = true;
855         return token;
856     case Identifier:
857         token = -1;
858         if (! identifierWithEscapedUnicode)
859             token = findReservedWord(buffer16, pos16);
860
861         if (token < 0) {
862             /* TODO: close leak on parse error. same holds true for String */
863             if (driver)
864                 qsyylval.ustr = driver->intern(buffer16, pos16);
865             else
866                 qsyylval.ustr = 0;
867             return QmlJSGrammar::T_IDENTIFIER;
868         }
869         if (token == QmlJSGrammar::T_CONTINUE || token == QmlJSGrammar::T_BREAK
870             || token == QmlJSGrammar::T_RETURN || token == QmlJSGrammar::T_THROW) {
871             restrKeyword = true;
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;
878         }
879         return token;
880     case String:
881         if (driver)
882             qsyylval.ustr = driver->intern(buffer16, pos16);
883         else
884             qsyylval.ustr = 0;
885         return multiLineString?QmlJSGrammar::T_MULTILINE_STRING_LITERAL:QmlJSGrammar::T_STRING_LITERAL;
886     case Number:
887         qsyylval.dval = dval;
888         return QmlJSGrammar::T_NUMERIC_LITERAL;
889     case Bad:
890         return -1;
891     default:
892         Q_ASSERT(!"unhandled numeration value in switch");
893         return -1;
894     }
895 }
896
897 bool Lexer::isWhiteSpace() const
898 {
899     return (current == ' ' || current == '\t' ||
900              current == 0x0b || current == 0x0c);
901 }
902
903 bool Lexer::isLineTerminator() const
904 {
905     return (current == '\n' || current == '\r');
906 }
907
908 bool Lexer::isIdentLetter(ushort c)
909 {
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')
914             || c == '$'
915             || c == '_')
916         return true;
917     if (c < 128)
918         return false;
919     return QChar(c).isLetterOrNumber();
920 }
921
922 bool Lexer::isDecimalDigit(ushort c)
923 {
924     return (c >= '0' && c <= '9');
925 }
926
927 bool Lexer::isHexDigit(ushort c) const
928 {
929     return ((c >= '0' && c <= '9')
930             || (c >= 'a' && c <= 'f')
931             || (c >= 'A' && c <= 'F'));
932 }
933
934 bool Lexer::isOctalDigit(ushort c) const
935 {
936     return (c >= '0' && c <= '7');
937 }
938
939 int Lexer::matchPunctuator(ushort c1, ushort c2,
940                             ushort c3, ushort c4)
941 {
942     if (c1 == '>' && c2 == '>' && c3 == '>' && c4 == '=') {
943         shift(4);
944         return QmlJSGrammar::T_GT_GT_GT_EQ;
945     } else if (c1 == '=' && c2 == '=' && c3 == '=') {
946         shift(3);
947         return QmlJSGrammar::T_EQ_EQ_EQ;
948     } else if (c1 == '!' && c2 == '=' && c3 == '=') {
949         shift(3);
950         return QmlJSGrammar::T_NOT_EQ_EQ;
951     } else if (c1 == '>' && c2 == '>' && c3 == '>') {
952         shift(3);
953         return QmlJSGrammar::T_GT_GT_GT;
954     } else if (c1 == '<' && c2 == '<' && c3 == '=') {
955         shift(3);
956         return QmlJSGrammar::T_LT_LT_EQ;
957     } else if (c1 == '>' && c2 == '>' && c3 == '=') {
958         shift(3);
959         return QmlJSGrammar::T_GT_GT_EQ;
960     } else if (c1 == '<' && c2 == '=') {
961         shift(2);
962         return QmlJSGrammar::T_LE;
963     } else if (c1 == '>' && c2 == '=') {
964         shift(2);
965         return QmlJSGrammar::T_GE;
966     } else if (c1 == '!' && c2 == '=') {
967         shift(2);
968         return QmlJSGrammar::T_NOT_EQ;
969     } else if (c1 == '+' && c2 == '+') {
970         shift(2);
971         return QmlJSGrammar::T_PLUS_PLUS;
972     } else if (c1 == '-' && c2 == '-') {
973         shift(2);
974         return QmlJSGrammar::T_MINUS_MINUS;
975     } else if (c1 == '=' && c2 == '=') {
976         shift(2);
977         return QmlJSGrammar::T_EQ_EQ;
978     } else if (c1 == '+' && c2 == '=') {
979         shift(2);
980         return QmlJSGrammar::T_PLUS_EQ;
981     } else if (c1 == '-' && c2 == '=') {
982         shift(2);
983         return QmlJSGrammar::T_MINUS_EQ;
984     } else if (c1 == '*' && c2 == '=') {
985         shift(2);
986         return QmlJSGrammar::T_STAR_EQ;
987     } else if (c1 == '/' && c2 == '=') {
988         shift(2);
989         return QmlJSGrammar::T_DIVIDE_EQ;
990     } else if (c1 == '&' && c2 == '=') {
991         shift(2);
992         return QmlJSGrammar::T_AND_EQ;
993     } else if (c1 == '^' && c2 == '=') {
994         shift(2);
995         return QmlJSGrammar::T_XOR_EQ;
996     } else if (c1 == '%' && c2 == '=') {
997         shift(2);
998         return QmlJSGrammar::T_REMAINDER_EQ;
999     } else if (c1 == '|' && c2 == '=') {
1000         shift(2);
1001         return QmlJSGrammar::T_OR_EQ;
1002     } else if (c1 == '<' && c2 == '<') {
1003         shift(2);
1004         return QmlJSGrammar::T_LT_LT;
1005     } else if (c1 == '>' && c2 == '>') {
1006         shift(2);
1007         return QmlJSGrammar::T_GT_GT;
1008     } else if (c1 == '&' && c2 == '&') {
1009         shift(2);
1010         return QmlJSGrammar::T_AND_AND;
1011     } else if (c1 == '|' && c2 == '|') {
1012         shift(2);
1013         return QmlJSGrammar::T_OR_OR;
1014     }
1015
1016     switch(c1) {
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;
1041
1042         default: return -1;
1043     }
1044 }
1045
1046 ushort Lexer::singleEscape(ushort c) const
1047 {
1048     switch(c) {
1049     case 'b':
1050         return 0x08;
1051     case 't':
1052         return 0x09;
1053     case 'n':
1054         return 0x0A;
1055     case 'v':
1056         return 0x0B;
1057     case 'f':
1058         return 0x0C;
1059     case 'r':
1060         return 0x0D;
1061     case '"':
1062         return 0x22;
1063     case '\'':
1064         return 0x27;
1065     case '\\':
1066         return 0x5C;
1067     default:
1068         return c;
1069     }
1070 }
1071
1072 ushort Lexer::convertOctal(ushort c1, ushort c2,
1073                             ushort c3) const
1074 {
1075     return ((c1 - '0') * 64 + (c2 - '0') * 8 + c3 - '0');
1076 }
1077
1078 unsigned char Lexer::convertHex(ushort c)
1079 {
1080     if (c >= '0' && c <= '9')
1081         return (c - '0');
1082     else if (c >= 'a' && c <= 'f')
1083         return (c - 'a' + 10);
1084     else
1085         return (c - 'A' + 10);
1086 }
1087
1088 unsigned char Lexer::convertHex(ushort c1, ushort c2)
1089 {
1090     return ((convertHex(c1) << 4) + convertHex(c2));
1091 }
1092
1093 QChar Lexer::convertUnicode(ushort c1, ushort c2,
1094                              ushort c3, ushort c4)
1095 {
1096     return QChar((convertHex(c3) << 4) + convertHex(c4),
1097                   (convertHex(c1) << 4) + convertHex(c2));
1098 }
1099
1100 void Lexer::record8(ushort c)
1101 {
1102     Q_ASSERT(c <= 0xff);
1103
1104     // enlarge buffer if full
1105     if (pos8 >= size8 - 1) {
1106         char *tmp = new char[2 * size8];
1107         memcpy(tmp, buffer8, size8 * sizeof(char));
1108         delete [] buffer8;
1109         buffer8 = tmp;
1110         size8 *= 2;
1111     }
1112
1113     buffer8[pos8++] = (char) c;
1114 }
1115
1116 void Lexer::record16(QChar c)
1117 {
1118     // enlarge buffer if full
1119     if (pos16 >= size16 - 1) {
1120         QChar *tmp = new QChar[2 * size16];
1121         memcpy(tmp, buffer16, size16 * sizeof(QChar));
1122         delete [] buffer16;
1123         buffer16 = tmp;
1124         size16 *= 2;
1125     }
1126
1127     buffer16[pos16++] = c;
1128 }
1129
1130 void Lexer::recordStartPos()
1131 {
1132     startpos = pos;
1133     startlineno = yylineno;
1134     startcolumn = yycolumn;
1135 }
1136
1137 bool Lexer::scanRegExp(RegExpBodyPrefix prefix)
1138 {
1139     pos16 = 0;
1140     pattern = 0;
1141
1142     if (prefix == EqualPrefix)
1143         record16(QLatin1Char('='));
1144
1145     while (true) {
1146         switch (current) {
1147
1148         case 0: // eof
1149         case '\n': case '\r': // line terminator
1150             errmsg = QCoreApplication::translate("QmlParser", "Unterminated regular expression literal");
1151             return false;
1152
1153         case '/':
1154             shift(1);
1155
1156             if (driver) // create the pattern
1157                 pattern = driver->intern(buffer16, pos16);
1158
1159             // scan the flags
1160             pos16 = 0;
1161             flags = 0;
1162             while (isIdentLetter(current)) {
1163                 int flag = Ecma::RegExp::flagFromChar(current);
1164                 if (flag == 0) {
1165                     errmsg = QCoreApplication::translate("QmlParser", "Invalid regular expression flag '%0'")
1166                              .arg(QChar(current));
1167                     return false;
1168                 }
1169                 flags |= flag;
1170                 record16(current);
1171                 shift(1);
1172             }
1173             return true;
1174
1175         case '\\':
1176             // regular expression backslash sequence
1177             record16(current);
1178             shift(1);
1179
1180             if (! current || isLineTerminator()) {
1181                 errmsg = QCoreApplication::translate("QmlParser", "Unterminated regular expression backslash sequence");
1182                 return false;
1183             }
1184
1185             record16(current);
1186             shift(1);
1187             break;
1188
1189         case '[':
1190             // regular expression class
1191             record16(current);
1192             shift(1);
1193
1194             while (current && ! isLineTerminator()) {
1195                 if (current == ']')
1196                     break;
1197                 else if (current == '\\') {
1198                     // regular expression backslash sequence
1199                     record16(current);
1200                     shift(1);
1201
1202                     if (! current || isLineTerminator()) {
1203                         errmsg = QCoreApplication::translate("QmlParser", "Unterminated regular expression backslash sequence");
1204                         return false;
1205                     }
1206
1207                     record16(current);
1208                     shift(1);
1209                 } else {
1210                     record16(current);
1211                     shift(1);
1212                 }
1213             }
1214
1215             if (current != ']') {
1216                 errmsg = QCoreApplication::translate("QmlParser", "Unterminated regular expression class");
1217                 return false;
1218             }
1219
1220             record16(current);
1221             shift(1); // skip ]
1222             break;
1223
1224         default:
1225             record16(current);
1226             shift(1);
1227         } // switch
1228     } // while
1229
1230     return false;
1231 }
1232
1233 void Lexer::syncProhibitAutomaticSemicolon()
1234 {
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;
1241     } else {
1242         prohibitAutomaticSemicolon = false;
1243     }
1244 }
1245
1246 QT_QML_END_NAMESPACE
1247
1248