Don't hide errors in QDirIterator
[qt-netbsd.git] / src / script / qscriptlexer.cpp
blobc6a8d82513ee2c5fc494da2137e5579d5786fc68
1 /****************************************************************************
2 **
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: Nokia Corporation (qt-info@nokia.com)
5 **
6 ** This file is part of the QtScript module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** No Commercial Usage
10 ** This file contains pre-release code and may not be distributed.
11 ** You may use this file in accordance with the terms and conditions
12 ** contained in the either Technology Preview License Agreement or the
13 ** Beta Release License Agreement.
15 ** GNU Lesser General Public License Usage
16 ** Alternatively, this file may be used under the terms of the GNU Lesser
17 ** General Public License version 2.1 as published by the Free Software
18 ** Foundation and appearing in the file LICENSE.LGPL included in the
19 ** packaging of this file. Please review the following information to
20 ** ensure the GNU Lesser General Public License version 2.1 requirements
21 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 ** In addition, as a special exception, Nokia gives you certain
24 ** additional rights. These rights are described in the Nokia Qt LGPL
25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26 ** package.
28 ** GNU General Public License Usage
29 ** Alternatively, this file may be used under the terms of the GNU
30 ** General Public License version 3.0 as published by the Free Software
31 ** Foundation and appearing in the file LICENSE.GPL included in the
32 ** packaging of this file. Please review the following information to
33 ** ensure the GNU General Public License version 3.0 requirements will be
34 ** met: http://www.gnu.org/copyleft/gpl.html.
36 ** If you are unsure which license is appropriate for your use, please
37 ** contact the sales department at http://www.qtsoftware.com/contact.
38 ** $QT_END_LICENSE$
40 ****************************************************************************/
42 #ifdef HAVE_CONFIG_H
43 #include "config.h"
44 #endif
46 #include "qscriptengine_p.h"
48 #ifndef QT_NO_SCRIPT
50 #include "qscriptvalueimpl_p.h"
51 #include "qscriptcontext_p.h"
52 #include "qscriptmember_p.h"
53 #include "qscriptobject_p.h"
54 #include "qscriptlexer_p.h"
55 #include "qscriptgrammar_p.h"
57 #include <ctype.h>
58 #include <stdlib.h>
59 #include <stdio.h>
60 #include <string.h>
62 QT_BEGIN_NAMESPACE
64 extern double qstrtod(const char *s00, char const **se, bool *ok);
66 #define shiftWindowsLineBreak() \
67 do { \
68 if (((current == '\r') && (next1 == '\n')) \
69 || ((current == '\n') && (next1 == '\r'))) { \
70 shift(1); \
71 } \
72 } \
73 while (0)
75 namespace QScript {
76 extern qsreal integerFromString(const char *buf, int size, int radix);
79 QScript::Lexer::Lexer(QScriptEnginePrivate *eng)
80 : driver(eng),
81 yylineno(0),
82 done(false),
83 size8(128), size16(128),
84 pos8(0), pos16(0),
85 terminator(false),
86 restrKeyword(false),
87 delimited(false),
88 stackToken(-1),
89 state(Start),
90 pos(0),
91 code(0), length(0),
92 yycolumn(0),
93 startlineno(0), startcolumn(0),
94 bol(true),
95 current(0), next1(0), next2(0), next3(0),
96 err(NoError),
97 wantRx(false),
98 check_reserved(true),
99 parenthesesState(IgnoreParentheses),
100 parenthesesCount(0),
101 prohibitAutomaticSemicolon(false)
103 // allocate space for read buffers
104 buffer8 = new char[size8];
105 buffer16 = new QChar[size16];
106 pattern = 0;
107 flags = 0;
111 QScript::Lexer::~Lexer()
113 delete [] buffer8;
114 delete [] buffer16;
117 void QScript::Lexer::setCode(const QString &c, int lineno)
119 errmsg = QString();
120 yylineno = lineno;
121 yycolumn = 1;
122 restrKeyword = false;
123 delimited = false;
124 stackToken = -1;
125 pos = 0;
126 code = c.unicode();
127 length = c.length();
128 bol = true;
130 // read first characters
131 current = (length > 0) ? code[0].unicode() : 0;
132 next1 = (length > 1) ? code[1].unicode() : 0;
133 next2 = (length > 2) ? code[2].unicode() : 0;
134 next3 = (length > 3) ? code[3].unicode() : 0;
137 void QScript::Lexer::shift(uint p)
139 while (p--) {
140 ++pos;
141 ++yycolumn;
142 current = next1;
143 next1 = next2;
144 next2 = next3;
145 next3 = (pos + 3 < length) ? code[pos+3].unicode() : 0;
149 void QScript::Lexer::setDone(State s)
151 state = s;
152 done = true;
155 int QScript::Lexer::findReservedWord(const QChar *c, int size) const
157 switch (size) {
158 case 2: {
159 if (c[0] == QLatin1Char('d') && c[1] == QLatin1Char('o'))
160 return QScriptGrammar::T_DO;
161 else if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('f'))
162 return QScriptGrammar::T_IF;
163 else if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('n'))
164 return QScriptGrammar::T_IN;
165 } break;
167 case 3: {
168 if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('o') && c[2] == QLatin1Char('r'))
169 return QScriptGrammar::T_FOR;
170 else if (c[0] == QLatin1Char('n') && c[1] == QLatin1Char('e') && c[2] == QLatin1Char('w'))
171 return QScriptGrammar::T_NEW;
172 else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('r') && c[2] == QLatin1Char('y'))
173 return QScriptGrammar::T_TRY;
174 else if (c[0] == QLatin1Char('v') && c[1] == QLatin1Char('a') && c[2] == QLatin1Char('r'))
175 return QScriptGrammar::T_VAR;
176 else if (check_reserved) {
177 if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('n') && c[2] == QLatin1Char('t'))
178 return QScriptGrammar::T_RESERVED_WORD;
180 } break;
182 case 4: {
183 if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('a')
184 && c[2] == QLatin1Char('s') && c[3] == QLatin1Char('e'))
185 return QScriptGrammar::T_CASE;
186 else if (c[0] == QLatin1Char('e') && c[1] == QLatin1Char('l')
187 && c[2] == QLatin1Char('s') && c[3] == QLatin1Char('e'))
188 return QScriptGrammar::T_ELSE;
189 else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('h')
190 && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('s'))
191 return QScriptGrammar::T_THIS;
192 else if (c[0] == QLatin1Char('v') && c[1] == QLatin1Char('o')
193 && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('d'))
194 return QScriptGrammar::T_VOID;
195 else if (c[0] == QLatin1Char('w') && c[1] == QLatin1Char('i')
196 && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('h'))
197 return QScriptGrammar::T_WITH;
198 else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('r')
199 && c[2] == QLatin1Char('u') && c[3] == QLatin1Char('e'))
200 return QScriptGrammar::T_TRUE;
201 else if (c[0] == QLatin1Char('n') && c[1] == QLatin1Char('u')
202 && c[2] == QLatin1Char('l') && c[3] == QLatin1Char('l'))
203 return QScriptGrammar::T_NULL;
204 else if (check_reserved) {
205 if (c[0] == QLatin1Char('e') && c[1] == QLatin1Char('n')
206 && c[2] == QLatin1Char('u') && c[3] == QLatin1Char('m'))
207 return QScriptGrammar::T_RESERVED_WORD;
208 else if (c[0] == QLatin1Char('b') && c[1] == QLatin1Char('y')
209 && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('e'))
210 return QScriptGrammar::T_RESERVED_WORD;
211 else if (c[0] == QLatin1Char('l') && c[1] == QLatin1Char('o')
212 && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('g'))
213 return QScriptGrammar::T_RESERVED_WORD;
214 else if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('h')
215 && c[2] == QLatin1Char('a') && c[3] == QLatin1Char('r'))
216 return QScriptGrammar::T_RESERVED_WORD;
217 else if (c[0] == QLatin1Char('g') && c[1] == QLatin1Char('o')
218 && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('o'))
219 return QScriptGrammar::T_RESERVED_WORD;
221 } break;
223 case 5: {
224 if (c[0] == QLatin1Char('b') && c[1] == QLatin1Char('r')
225 && c[2] == QLatin1Char('e') && c[3] == QLatin1Char('a')
226 && c[4] == QLatin1Char('k'))
227 return QScriptGrammar::T_BREAK;
228 else if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('a')
229 && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('c')
230 && c[4] == QLatin1Char('h'))
231 return QScriptGrammar::T_CATCH;
232 else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('h')
233 && c[2] == QLatin1Char('r') && c[3] == QLatin1Char('o')
234 && c[4] == QLatin1Char('w'))
235 return QScriptGrammar::T_THROW;
236 else if (c[0] == QLatin1Char('w') && c[1] == QLatin1Char('h')
237 && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('l')
238 && c[4] == QLatin1Char('e'))
239 return QScriptGrammar::T_WHILE;
240 else if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('o')
241 && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('s')
242 && c[4] == QLatin1Char('t'))
243 return QScriptGrammar::T_CONST;
244 else if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('a')
245 && c[2] == QLatin1Char('l') && c[3] == QLatin1Char('s')
246 && c[4] == QLatin1Char('e'))
247 return QScriptGrammar::T_FALSE;
248 else if (check_reserved) {
249 if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('h')
250 && c[2] == QLatin1Char('o') && c[3] == QLatin1Char('r')
251 && c[4] == QLatin1Char('t'))
252 return QScriptGrammar::T_RESERVED_WORD;
253 else if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('u')
254 && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('e')
255 && c[4] == QLatin1Char('r'))
256 return QScriptGrammar::T_RESERVED_WORD;
257 else if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('i')
258 && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('a')
259 && c[4] == QLatin1Char('l'))
260 return QScriptGrammar::T_RESERVED_WORD;
261 else if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('l')
262 && c[2] == QLatin1Char('a') && c[3] == QLatin1Char('s')
263 && c[4] == QLatin1Char('s'))
264 return QScriptGrammar::T_RESERVED_WORD;
265 else if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('l')
266 && c[2] == QLatin1Char('o') && c[3] == QLatin1Char('a')
267 && c[4] == QLatin1Char('t'))
268 return QScriptGrammar::T_RESERVED_WORD;
270 } break;
272 case 6: {
273 if (c[0] == QLatin1Char('d') && c[1] == QLatin1Char('e')
274 && c[2] == QLatin1Char('l') && c[3] == QLatin1Char('e')
275 && c[4] == QLatin1Char('t') && c[5] == QLatin1Char('e'))
276 return QScriptGrammar::T_DELETE;
277 else if (c[0] == QLatin1Char('r') && c[1] == QLatin1Char('e')
278 && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('u')
279 && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('n'))
280 return QScriptGrammar::T_RETURN;
281 else if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('w')
282 && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('t')
283 && c[4] == QLatin1Char('c') && c[5] == QLatin1Char('h'))
284 return QScriptGrammar::T_SWITCH;
285 else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('y')
286 && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('e')
287 && c[4] == QLatin1Char('o') && c[5] == QLatin1Char('f'))
288 return QScriptGrammar::T_TYPEOF;
289 else if (check_reserved) {
290 if (c[0] == QLatin1Char('e') && c[1] == QLatin1Char('x')
291 && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('o')
292 && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('t'))
293 return QScriptGrammar::T_RESERVED_WORD;
294 else if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('t')
295 && c[2] == QLatin1Char('a') && c[3] == QLatin1Char('t')
296 && c[4] == QLatin1Char('i') && c[5] == QLatin1Char('c'))
297 return QScriptGrammar::T_RESERVED_WORD;
298 else if (c[0] == QLatin1Char('d') && c[1] == QLatin1Char('o')
299 && c[2] == QLatin1Char('u') && c[3] == QLatin1Char('b')
300 && c[4] == QLatin1Char('l') && c[5] == QLatin1Char('e'))
301 return QScriptGrammar::T_RESERVED_WORD;
302 else if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('m')
303 && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('o')
304 && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('t'))
305 return QScriptGrammar::T_RESERVED_WORD;
306 else if (c[0] == QLatin1Char('p') && c[1] == QLatin1Char('u')
307 && c[2] == QLatin1Char('b') && c[3] == QLatin1Char('l')
308 && c[4] == QLatin1Char('i') && c[5] == QLatin1Char('c'))
309 return QScriptGrammar::T_RESERVED_WORD;
310 else if (c[0] == QLatin1Char('n') && c[1] == QLatin1Char('a')
311 && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('i')
312 && c[4] == QLatin1Char('v') && c[5] == QLatin1Char('e'))
313 return QScriptGrammar::T_RESERVED_WORD;
314 else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('h')
315 && c[2] == QLatin1Char('r') && c[3] == QLatin1Char('o')
316 && c[4] == QLatin1Char('w') && c[5] == QLatin1Char('s'))
317 return QScriptGrammar::T_RESERVED_WORD;
319 } break;
321 case 7: {
322 if (c[0] == QLatin1Char('d') && c[1] == QLatin1Char('e')
323 && c[2] == QLatin1Char('f') && c[3] == QLatin1Char('a')
324 && c[4] == QLatin1Char('u') && c[5] == QLatin1Char('l')
325 && c[6] == QLatin1Char('t'))
326 return QScriptGrammar::T_DEFAULT;
327 else if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('i')
328 && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('a')
329 && c[4] == QLatin1Char('l') && c[5] == QLatin1Char('l')
330 && c[6] == QLatin1Char('y'))
331 return QScriptGrammar::T_FINALLY;
332 else if (check_reserved) {
333 if (c[0] == QLatin1Char('b') && c[1] == QLatin1Char('o')
334 && c[2] == QLatin1Char('o') && c[3] == QLatin1Char('l')
335 && c[4] == QLatin1Char('e') && c[5] == QLatin1Char('a')
336 && c[6] == QLatin1Char('n'))
337 return QScriptGrammar::T_RESERVED_WORD;
338 else if (c[0] == QLatin1Char('e') && c[1] == QLatin1Char('x')
339 && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('e')
340 && c[4] == QLatin1Char('n') && c[5] == QLatin1Char('d')
341 && c[6] == QLatin1Char('s'))
342 return QScriptGrammar::T_RESERVED_WORD;
343 else if (c[0] == QLatin1Char('p') && c[1] == QLatin1Char('a')
344 && c[2] == QLatin1Char('c') && c[3] == QLatin1Char('k')
345 && c[4] == QLatin1Char('a') && c[5] == QLatin1Char('g')
346 && c[6] == QLatin1Char('e'))
347 return QScriptGrammar::T_RESERVED_WORD;
348 else if (c[0] == QLatin1Char('p') && c[1] == QLatin1Char('r')
349 && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('v')
350 && c[4] == QLatin1Char('a') && c[5] == QLatin1Char('t')
351 && c[6] == QLatin1Char('e'))
352 return QScriptGrammar::T_RESERVED_WORD;
354 } break;
356 case 8: {
357 if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('o')
358 && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('t')
359 && c[4] == QLatin1Char('i') && c[5] == QLatin1Char('n')
360 && c[6] == QLatin1Char('u') && c[7] == QLatin1Char('e'))
361 return QScriptGrammar::T_CONTINUE;
362 else if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('u')
363 && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('c')
364 && c[4] == QLatin1Char('t') && c[5] == QLatin1Char('i')
365 && c[6] == QLatin1Char('o') && c[7] == QLatin1Char('n'))
366 return QScriptGrammar::T_FUNCTION;
367 else if (c[0] == QLatin1Char('d') && c[1] == QLatin1Char('e')
368 && c[2] == QLatin1Char('b') && c[3] == QLatin1Char('u')
369 && c[4] == QLatin1Char('g') && c[5] == QLatin1Char('g')
370 && c[6] == QLatin1Char('e') && c[7] == QLatin1Char('r'))
371 return QScriptGrammar::T_DEBUGGER;
372 else if (check_reserved) {
373 if (c[0] == QLatin1Char('a') && c[1] == QLatin1Char('b')
374 && c[2] == QLatin1Char('s') && c[3] == QLatin1Char('t')
375 && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('a')
376 && c[6] == QLatin1Char('c') && c[7] == QLatin1Char('t'))
377 return QScriptGrammar::T_RESERVED_WORD;
378 else if (c[0] == QLatin1Char('v') && c[1] == QLatin1Char('o')
379 && c[2] == QLatin1Char('l') && c[3] == QLatin1Char('a')
380 && c[4] == QLatin1Char('t') && c[5] == QLatin1Char('i')
381 && c[6] == QLatin1Char('l') && c[7] == QLatin1Char('e'))
382 return QScriptGrammar::T_RESERVED_WORD;
384 } break;
386 case 9: {
387 if (check_reserved) {
388 if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('n')
389 && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('e')
390 && c[4] == QLatin1Char('r') && c[5] == QLatin1Char('f')
391 && c[6] == QLatin1Char('a') && c[7] == QLatin1Char('c')
392 && c[8] == QLatin1Char('e'))
393 return QScriptGrammar::T_RESERVED_WORD;
394 else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('r')
395 && c[2] == QLatin1Char('a') && c[3] == QLatin1Char('n')
396 && c[4] == QLatin1Char('s') && c[5] == QLatin1Char('i')
397 && c[6] == QLatin1Char('e') && c[7] == QLatin1Char('n')
398 && c[8] == QLatin1Char('t'))
399 return QScriptGrammar::T_RESERVED_WORD;
400 else if (c[0] == QLatin1Char('p') && c[1] == QLatin1Char('r')
401 && c[2] == QLatin1Char('o') && c[3] == QLatin1Char('t')
402 && c[4] == QLatin1Char('e') && c[5] == QLatin1Char('c')
403 && c[6] == QLatin1Char('t') && c[7] == QLatin1Char('e')
404 && c[8] == QLatin1Char('d'))
405 return QScriptGrammar::T_RESERVED_WORD;
407 } break;
409 case 10: {
410 if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('n')
411 && c[2] == QLatin1Char('s') && c[3] == QLatin1Char('t')
412 && c[4] == QLatin1Char('a') && c[5] == QLatin1Char('n')
413 && c[6] == QLatin1Char('c') && c[7] == QLatin1Char('e')
414 && c[8] == QLatin1Char('o') && c[9] == QLatin1Char('f'))
415 return QScriptGrammar::T_INSTANCEOF;
416 else if (check_reserved) {
417 if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('m')
418 && c[2] == QLatin1Char('p') && c[3] == QLatin1Char('l')
419 && c[4] == QLatin1Char('e') && c[5] == QLatin1Char('m')
420 && c[6] == QLatin1Char('e') && c[7] == QLatin1Char('n')
421 && c[8] == QLatin1Char('t') && c[9] == QLatin1Char('s'))
422 return QScriptGrammar::T_RESERVED_WORD;
424 } break;
426 case 12: {
427 if (check_reserved) {
428 if (c[0] == QLatin1Char('s') && c[1] == QLatin1Char('y')
429 && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('c')
430 && c[4] == QLatin1Char('h') && c[5] == QLatin1Char('r')
431 && c[6] == QLatin1Char('o') && c[7] == QLatin1Char('n')
432 && c[8] == QLatin1Char('i') && c[9] == QLatin1Char('z')
433 && c[10] == QLatin1Char('e') && c[11] == QLatin1Char('d'))
434 return QScriptGrammar::T_RESERVED_WORD;
436 } break;
438 } // switch
440 return -1;
443 int QScript::Lexer::lex()
445 int token = 0;
446 state = Start;
447 ushort stringType = 0; // either single or double quotes
448 pos8 = pos16 = 0;
449 done = false;
450 terminator = false;
452 // did we push a token on the stack previously ?
453 // (after an automatic semicolon insertion)
454 if (stackToken >= 0) {
455 setDone(Other);
456 token = stackToken;
457 stackToken = -1;
460 while (!done) {
461 switch (state) {
462 case Start:
463 if (isWhiteSpace()) {
464 // do nothing
465 } else if (current == '/' && next1 == '/') {
466 recordStartPos();
467 shift(1);
468 state = InSingleLineComment;
469 } else if (current == '/' && next1 == '*') {
470 recordStartPos();
471 shift(1);
472 state = InMultiLineComment;
473 } else if (current == 0) {
474 syncProhibitAutomaticSemicolon();
475 if (!terminator && !delimited && !prohibitAutomaticSemicolon) {
476 // automatic semicolon insertion if program incomplete
477 token = QScriptGrammar::T_SEMICOLON;
478 stackToken = 0;
479 setDone(Other);
480 } else {
481 setDone(Eof);
483 } else if (isLineTerminator()) {
484 shiftWindowsLineBreak();
485 yylineno++;
486 yycolumn = 0;
487 bol = true;
488 terminator = true;
489 syncProhibitAutomaticSemicolon();
490 if (restrKeyword) {
491 token = QScriptGrammar::T_SEMICOLON;
492 setDone(Other);
494 } else if (current == '"' || current == '\'') {
495 recordStartPos();
496 state = InString;
497 stringType = current;
498 } else if (isIdentLetter(current)) {
499 recordStartPos();
500 record16(current);
501 state = InIdentifier;
502 } else if (current == '0') {
503 recordStartPos();
504 record8(current);
505 state = InNum0;
506 } else if (isDecimalDigit(current)) {
507 recordStartPos();
508 record8(current);
509 state = InNum;
510 } else if (current == '.' && isDecimalDigit(next1)) {
511 recordStartPos();
512 record8(current);
513 state = InDecimal;
514 } else {
515 recordStartPos();
516 token = matchPunctuator(current, next1, next2, next3);
517 if (token != -1) {
518 if (terminator && !delimited && !prohibitAutomaticSemicolon
519 && (token == QScriptGrammar::T_PLUS_PLUS
520 || token == QScriptGrammar::T_MINUS_MINUS)) {
521 // automatic semicolon insertion
522 stackToken = token;
523 token = QScriptGrammar::T_SEMICOLON;
525 setDone(Other);
527 else {
528 setDone(Bad);
529 err = IllegalCharacter;
530 errmsg = QLatin1String("Illegal character");
533 break;
534 case InString:
535 if (current == stringType) {
536 shift(1);
537 setDone(String);
538 } else if (current == 0 || isLineTerminator()) {
539 setDone(Bad);
540 err = UnclosedStringLiteral;
541 errmsg = QLatin1String("Unclosed string at end of line");
542 } else if (current == '\\') {
543 state = InEscapeSequence;
544 } else {
545 record16(current);
547 break;
548 // Escape Sequences inside of strings
549 case InEscapeSequence:
550 if (isOctalDigit(current)) {
551 if (current >= '0' && current <= '3' &&
552 isOctalDigit(next1) && isOctalDigit(next2)) {
553 record16(convertOctal(current, next1, next2));
554 shift(2);
555 state = InString;
556 } else if (isOctalDigit(current) &&
557 isOctalDigit(next1)) {
558 record16(convertOctal('0', current, next1));
559 shift(1);
560 state = InString;
561 } else if (isOctalDigit(current)) {
562 record16(convertOctal('0', '0', current));
563 state = InString;
564 } else {
565 setDone(Bad);
566 err = IllegalEscapeSequence;
567 errmsg = QLatin1String("Illegal escape squence");
569 } else if (current == 'x')
570 state = InHexEscape;
571 else if (current == 'u')
572 state = InUnicodeEscape;
573 else {
574 if (isLineTerminator()) {
575 shiftWindowsLineBreak();
576 yylineno++;
577 yycolumn = 0;
578 bol = true;
579 } else {
580 record16(singleEscape(current));
582 state = InString;
584 break;
585 case InHexEscape:
586 if (isHexDigit(current) && isHexDigit(next1)) {
587 state = InString;
588 record16(QLatin1Char(convertHex(current, next1)));
589 shift(1);
590 } else if (current == stringType) {
591 record16(QLatin1Char('x'));
592 shift(1);
593 setDone(String);
594 } else {
595 record16(QLatin1Char('x'));
596 record16(current);
597 state = InString;
599 break;
600 case InUnicodeEscape:
601 if (isHexDigit(current) && isHexDigit(next1) &&
602 isHexDigit(next2) && isHexDigit(next3)) {
603 record16(convertUnicode(current, next1, next2, next3));
604 shift(3);
605 state = InString;
606 } else if (current == stringType) {
607 record16(QLatin1Char('u'));
608 shift(1);
609 setDone(String);
610 } else {
611 setDone(Bad);
612 err = IllegalUnicodeEscapeSequence;
613 errmsg = QLatin1String("Illegal unicode escape sequence");
615 break;
616 case InSingleLineComment:
617 if (isLineTerminator()) {
618 shiftWindowsLineBreak();
619 yylineno++;
620 yycolumn = 0;
621 terminator = true;
622 bol = true;
623 if (restrKeyword) {
624 token = QScriptGrammar::T_SEMICOLON;
625 setDone(Other);
626 } else
627 state = Start;
628 } else if (current == 0) {
629 setDone(Eof);
631 break;
632 case InMultiLineComment:
633 if (current == 0) {
634 setDone(Bad);
635 err = UnclosedComment;
636 errmsg = QLatin1String("Unclosed comment at end of file");
637 } else if (isLineTerminator()) {
638 shiftWindowsLineBreak();
639 yylineno++;
640 } else if (current == '*' && next1 == '/') {
641 state = Start;
642 shift(1);
644 break;
645 case InIdentifier:
646 if (isIdentLetter(current) || isDecimalDigit(current)) {
647 record16(current);
648 break;
650 setDone(Identifier);
651 break;
652 case InNum0:
653 if (current == 'x' || current == 'X') {
654 record8(current);
655 state = InHex;
656 } else if (current == '.') {
657 record8(current);
658 state = InDecimal;
659 } else if (current == 'e' || current == 'E') {
660 record8(current);
661 state = InExponentIndicator;
662 } else if (isOctalDigit(current)) {
663 record8(current);
664 state = InOctal;
665 } else if (isDecimalDigit(current)) {
666 record8(current);
667 state = InDecimal;
668 } else {
669 setDone(Number);
671 break;
672 case InHex:
673 if (isHexDigit(current))
674 record8(current);
675 else
676 setDone(Hex);
677 break;
678 case InOctal:
679 if (isOctalDigit(current)) {
680 record8(current);
681 } else if (isDecimalDigit(current)) {
682 record8(current);
683 state = InDecimal;
684 } else {
685 setDone(Octal);
687 break;
688 case InNum:
689 if (isDecimalDigit(current)) {
690 record8(current);
691 } else if (current == '.') {
692 record8(current);
693 state = InDecimal;
694 } else if (current == 'e' || current == 'E') {
695 record8(current);
696 state = InExponentIndicator;
697 } else {
698 setDone(Number);
700 break;
701 case InDecimal:
702 if (isDecimalDigit(current)) {
703 record8(current);
704 } else if (current == 'e' || current == 'E') {
705 record8(current);
706 state = InExponentIndicator;
707 } else {
708 setDone(Number);
710 break;
711 case InExponentIndicator:
712 if (current == '+' || current == '-') {
713 record8(current);
714 } else if (isDecimalDigit(current)) {
715 record8(current);
716 state = InExponent;
717 } else {
718 setDone(Bad);
719 err = IllegalExponentIndicator;
720 errmsg = QLatin1String("Illegal syntax for exponential number");
722 break;
723 case InExponent:
724 if (isDecimalDigit(current)) {
725 record8(current);
726 } else {
727 setDone(Number);
729 break;
730 default:
731 Q_ASSERT_X(0, "Lexer::lex", "Unhandled state in switch statement");
734 // move on to the next character
735 if (!done)
736 shift(1);
737 if (state != Start && state != InSingleLineComment)
738 bol = false;
741 // no identifiers allowed directly after numeric literal, e.g. "3in" is bad
742 if ((state == Number || state == Octal || state == Hex)
743 && isIdentLetter(current)) {
744 state = Bad;
745 err = IllegalIdentifier;
746 errmsg = QLatin1String("Identifier cannot start with numeric literal");
749 // terminate string
750 buffer8[pos8] = '\0';
752 double dval = 0;
753 if (state == Number) {
754 dval = qstrtod(buffer8, 0, 0);
755 } else if (state == Hex) { // scan hex numbers
756 dval = QScript::integerFromString(buffer8, pos8, 16);
757 state = Number;
758 } else if (state == Octal) { // scan octal number
759 dval = QScript::integerFromString(buffer8, pos8, 8);
760 state = Number;
763 restrKeyword = false;
764 delimited = false;
766 switch (parenthesesState) {
767 case IgnoreParentheses:
768 break;
769 case CountParentheses:
770 if (token == QScriptGrammar::T_RPAREN) {
771 --parenthesesCount;
772 if (parenthesesCount == 0)
773 parenthesesState = BalancedParentheses;
774 } else if (token == QScriptGrammar::T_LPAREN) {
775 ++parenthesesCount;
777 break;
778 case BalancedParentheses:
779 parenthesesState = IgnoreParentheses;
780 break;
783 switch (state) {
784 case Eof:
785 return 0;
786 case Other:
787 if(token == QScriptGrammar::T_RBRACE || token == QScriptGrammar::T_SEMICOLON)
788 delimited = true;
789 return token;
790 case Identifier:
791 if ((token = findReservedWord(buffer16, pos16)) < 0) {
792 /* TODO: close leak on parse error. same holds true for String */
793 if (driver)
794 qsyylval.ustr = driver->intern(buffer16, pos16);
795 else
796 qsyylval.ustr = 0;
797 return QScriptGrammar::T_IDENTIFIER;
799 if (token == QScriptGrammar::T_CONTINUE || token == QScriptGrammar::T_BREAK
800 || token == QScriptGrammar::T_RETURN || token == QScriptGrammar::T_THROW) {
801 restrKeyword = true;
802 } else if (token == QScriptGrammar::T_IF || token == QScriptGrammar::T_FOR
803 || token == QScriptGrammar::T_WHILE || token == QScriptGrammar::T_WITH) {
804 parenthesesState = CountParentheses;
805 parenthesesCount = 0;
806 } else if (token == QScriptGrammar::T_DO) {
807 parenthesesState = BalancedParentheses;
809 return token;
810 case String:
811 if (driver)
812 qsyylval.ustr = driver->intern(buffer16, pos16);
813 else
814 qsyylval.ustr = 0;
815 return QScriptGrammar::T_STRING_LITERAL;
816 case Number:
817 qsyylval.dval = dval;
818 return QScriptGrammar::T_NUMERIC_LITERAL;
819 case Bad:
820 return -1;
821 default:
822 Q_ASSERT(!"unhandled numeration value in switch");
823 return -1;
827 bool QScript::Lexer::isWhiteSpace() const
829 return (current == ' ' || current == '\t' ||
830 current == 0x0b || current == 0x0c);
833 bool QScript::Lexer::isLineTerminator() const
835 return (current == '\n' || current == '\r');
838 bool QScript::Lexer::isIdentLetter(ushort c)
840 /* TODO: allow other legitimate unicode chars */
841 return ((c >= 'a' && c <= 'z')
842 || (c >= 'A' && c <= 'Z')
843 || c == '$'
844 || c == '_');
847 bool QScript::Lexer::isDecimalDigit(ushort c)
849 return (c >= '0' && c <= '9');
852 bool QScript::Lexer::isHexDigit(ushort c) const
854 return ((c >= '0' && c <= '9')
855 || (c >= 'a' && c <= 'f')
856 || (c >= 'A' && c <= 'F'));
859 bool QScript::Lexer::isOctalDigit(ushort c) const
861 return (c >= '0' && c <= '7');
864 int QScript::Lexer::matchPunctuator(ushort c1, ushort c2,
865 ushort c3, ushort c4)
867 if (c1 == '>' && c2 == '>' && c3 == '>' && c4 == '=') {
868 shift(4);
869 return QScriptGrammar::T_GT_GT_GT_EQ;
870 } else if (c1 == '=' && c2 == '=' && c3 == '=') {
871 shift(3);
872 return QScriptGrammar::T_EQ_EQ_EQ;
873 } else if (c1 == '!' && c2 == '=' && c3 == '=') {
874 shift(3);
875 return QScriptGrammar::T_NOT_EQ_EQ;
876 } else if (c1 == '>' && c2 == '>' && c3 == '>') {
877 shift(3);
878 return QScriptGrammar::T_GT_GT_GT;
879 } else if (c1 == '<' && c2 == '<' && c3 == '=') {
880 shift(3);
881 return QScriptGrammar::T_LT_LT_EQ;
882 } else if (c1 == '>' && c2 == '>' && c3 == '=') {
883 shift(3);
884 return QScriptGrammar::T_GT_GT_EQ;
885 } else if (c1 == '<' && c2 == '=') {
886 shift(2);
887 return QScriptGrammar::T_LE;
888 } else if (c1 == '>' && c2 == '=') {
889 shift(2);
890 return QScriptGrammar::T_GE;
891 } else if (c1 == '!' && c2 == '=') {
892 shift(2);
893 return QScriptGrammar::T_NOT_EQ;
894 } else if (c1 == '+' && c2 == '+') {
895 shift(2);
896 return QScriptGrammar::T_PLUS_PLUS;
897 } else if (c1 == '-' && c2 == '-') {
898 shift(2);
899 return QScriptGrammar::T_MINUS_MINUS;
900 } else if (c1 == '=' && c2 == '=') {
901 shift(2);
902 return QScriptGrammar::T_EQ_EQ;
903 } else if (c1 == '+' && c2 == '=') {
904 shift(2);
905 return QScriptGrammar::T_PLUS_EQ;
906 } else if (c1 == '-' && c2 == '=') {
907 shift(2);
908 return QScriptGrammar::T_MINUS_EQ;
909 } else if (c1 == '*' && c2 == '=') {
910 shift(2);
911 return QScriptGrammar::T_STAR_EQ;
912 } else if (c1 == '/' && c2 == '=') {
913 shift(2);
914 return QScriptGrammar::T_DIVIDE_EQ;
915 } else if (c1 == '&' && c2 == '=') {
916 shift(2);
917 return QScriptGrammar::T_AND_EQ;
918 } else if (c1 == '^' && c2 == '=') {
919 shift(2);
920 return QScriptGrammar::T_XOR_EQ;
921 } else if (c1 == '%' && c2 == '=') {
922 shift(2);
923 return QScriptGrammar::T_REMAINDER_EQ;
924 } else if (c1 == '|' && c2 == '=') {
925 shift(2);
926 return QScriptGrammar::T_OR_EQ;
927 } else if (c1 == '<' && c2 == '<') {
928 shift(2);
929 return QScriptGrammar::T_LT_LT;
930 } else if (c1 == '>' && c2 == '>') {
931 shift(2);
932 return QScriptGrammar::T_GT_GT;
933 } else if (c1 == '&' && c2 == '&') {
934 shift(2);
935 return QScriptGrammar::T_AND_AND;
936 } else if (c1 == '|' && c2 == '|') {
937 shift(2);
938 return QScriptGrammar::T_OR_OR;
941 switch(c1) {
942 case '=': shift(1); return QScriptGrammar::T_EQ;
943 case '>': shift(1); return QScriptGrammar::T_GT;
944 case '<': shift(1); return QScriptGrammar::T_LT;
945 case ',': shift(1); return QScriptGrammar::T_COMMA;
946 case '!': shift(1); return QScriptGrammar::T_NOT;
947 case '~': shift(1); return QScriptGrammar::T_TILDE;
948 case '?': shift(1); return QScriptGrammar::T_QUESTION;
949 case ':': shift(1); return QScriptGrammar::T_COLON;
950 case '.': shift(1); return QScriptGrammar::T_DOT;
951 case '+': shift(1); return QScriptGrammar::T_PLUS;
952 case '-': shift(1); return QScriptGrammar::T_MINUS;
953 case '*': shift(1); return QScriptGrammar::T_STAR;
954 case '/': shift(1); return QScriptGrammar::T_DIVIDE_;
955 case '&': shift(1); return QScriptGrammar::T_AND;
956 case '|': shift(1); return QScriptGrammar::T_OR;
957 case '^': shift(1); return QScriptGrammar::T_XOR;
958 case '%': shift(1); return QScriptGrammar::T_REMAINDER;
959 case '(': shift(1); return QScriptGrammar::T_LPAREN;
960 case ')': shift(1); return QScriptGrammar::T_RPAREN;
961 case '{': shift(1); return QScriptGrammar::T_LBRACE;
962 case '}': shift(1); return QScriptGrammar::T_RBRACE;
963 case '[': shift(1); return QScriptGrammar::T_LBRACKET;
964 case ']': shift(1); return QScriptGrammar::T_RBRACKET;
965 case ';': shift(1); return QScriptGrammar::T_SEMICOLON;
967 default: return -1;
971 ushort QScript::Lexer::singleEscape(ushort c) const
973 switch(c) {
974 case 'b':
975 return 0x08;
976 case 't':
977 return 0x09;
978 case 'n':
979 return 0x0A;
980 case 'v':
981 return 0x0B;
982 case 'f':
983 return 0x0C;
984 case 'r':
985 return 0x0D;
986 case '"':
987 return 0x22;
988 case '\'':
989 return 0x27;
990 case '\\':
991 return 0x5C;
992 default:
993 return c;
997 ushort QScript::Lexer::convertOctal(ushort c1, ushort c2,
998 ushort c3) const
1000 return ((c1 - '0') * 64 + (c2 - '0') * 8 + c3 - '0');
1003 unsigned char QScript::Lexer::convertHex(ushort c)
1005 if (c >= '0' && c <= '9')
1006 return (c - '0');
1007 else if (c >= 'a' && c <= 'f')
1008 return (c - 'a' + 10);
1009 else
1010 return (c - 'A' + 10);
1013 unsigned char QScript::Lexer::convertHex(ushort c1, ushort c2)
1015 return ((convertHex(c1) << 4) + convertHex(c2));
1018 QChar QScript::Lexer::convertUnicode(ushort c1, ushort c2,
1019 ushort c3, ushort c4)
1021 return QChar((convertHex(c3) << 4) + convertHex(c4),
1022 (convertHex(c1) << 4) + convertHex(c2));
1025 void QScript::Lexer::record8(ushort c)
1027 Q_ASSERT(c <= 0xff);
1029 // enlarge buffer if full
1030 if (pos8 >= size8 - 1) {
1031 char *tmp = new char[2 * size8];
1032 memcpy(tmp, buffer8, size8 * sizeof(char));
1033 delete [] buffer8;
1034 buffer8 = tmp;
1035 size8 *= 2;
1038 buffer8[pos8++] = (char) c;
1041 void QScript::Lexer::record16(QChar c)
1043 // enlarge buffer if full
1044 if (pos16 >= size16 - 1) {
1045 QChar *tmp = new QChar[2 * size16];
1046 memcpy(tmp, buffer16, size16 * sizeof(QChar));
1047 delete [] buffer16;
1048 buffer16 = tmp;
1049 size16 *= 2;
1052 buffer16[pos16++] = c;
1055 void QScript::Lexer::recordStartPos()
1057 startlineno = yylineno;
1058 startcolumn = yycolumn;
1061 bool QScript::Lexer::scanRegExp(RegExpBodyPrefix prefix)
1063 pos16 = 0;
1064 bool lastWasEscape = false;
1066 if (prefix == EqualPrefix)
1067 record16(QLatin1Char('='));
1069 while (1) {
1070 if (isLineTerminator() || current == 0) {
1071 errmsg = QLatin1String("Unterminated regular expression literal");
1072 return false;
1074 else if (current != '/' || lastWasEscape == true)
1076 record16(current);
1077 lastWasEscape = !lastWasEscape && (current == '\\');
1079 else {
1080 if (driver)
1081 pattern = driver->intern(buffer16, pos16);
1082 else
1083 pattern = 0;
1084 pos16 = 0;
1085 shift(1);
1086 break;
1088 shift(1);
1091 flags = 0;
1092 while (isIdentLetter(current)) {
1093 int flag = QScript::Ecma::RegExp::flagFromChar(current);
1094 if (flag == 0) {
1095 errmsg = QString::fromLatin1("Invalid regular expression flag '%0'")
1096 .arg(QChar(current));
1097 return false;
1099 flags |= flag;
1100 record16(current);
1101 shift(1);
1104 return true;
1107 void QScript::Lexer::syncProhibitAutomaticSemicolon()
1109 if (parenthesesState == BalancedParentheses) {
1110 // we have seen something like "if (foo)", which means we should
1111 // never insert an automatic semicolon at this point, since it would
1112 // then be expanded into an empty statement (ECMA-262 7.9.1)
1113 prohibitAutomaticSemicolon = true;
1114 parenthesesState = IgnoreParentheses;
1115 } else {
1116 prohibitAutomaticSemicolon = false;
1120 QT_END_NAMESPACE
1122 #endif // QT_NO_SCRIPT