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