Qt 4.8
qdeclarativejslexer.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtDeclarative module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
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 
60 Q_CORE_EXPORT double qstrtod(const char *s00, char const **se, bool *ok);
62 
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 
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 
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 
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'))
165  else if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('f'))
167  else if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('n'))
169  else if (c[0] == QLatin1Char('a') && c[1] == QLatin1Char('s'))
171  else if (c[0] == QLatin1Char('o') && c[1] == QLatin1Char('n'))
173  } break;
174 
175  case 3: {
176  if (c[0] == QLatin1Char('f') && c[1] == QLatin1Char('o') && c[2] == QLatin1Char('r'))
178  else if (c[0] == QLatin1Char('n') && c[1] == QLatin1Char('e') && c[2] == QLatin1Char('w'))
180  else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('r') && c[2] == QLatin1Char('y'))
182  else if (c[0] == QLatin1Char('v') && c[1] == QLatin1Char('a') && c[2] == QLatin1Char('r'))
184  else if (check_reserved) {
185  if (c[0] == QLatin1Char('i') && c[1] == QLatin1Char('n') && c[2] == QLatin1Char('t'))
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'))
194  else if (c[0] == QLatin1Char('e') && c[1] == QLatin1Char('l')
195  && c[2] == QLatin1Char('s') && c[3] == QLatin1Char('e'))
197  else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('h')
198  && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('s'))
200  else if (c[0] == QLatin1Char('v') && c[1] == QLatin1Char('o')
201  && c[2] == QLatin1Char('i') && c[3] == QLatin1Char('d'))
203  else if (c[0] == QLatin1Char('w') && c[1] == QLatin1Char('i')
204  && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('h'))
206  else if (c[0] == QLatin1Char('t') && c[1] == QLatin1Char('r')
207  && c[2] == QLatin1Char('u') && c[3] == QLatin1Char('e'))
209  else if (c[0] == QLatin1Char('n') && c[1] == QLatin1Char('u')
210  && c[2] == QLatin1Char('l') && c[3] == QLatin1Char('l'))
212  else if (check_reserved) {
213  if (c[0] == QLatin1Char('e') && c[1] == QLatin1Char('n')
214  && c[2] == QLatin1Char('u') && c[3] == QLatin1Char('m'))
216  else if (c[0] == QLatin1Char('b') && c[1] == QLatin1Char('y')
217  && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('e'))
219  else if (c[0] == QLatin1Char('l') && c[1] == QLatin1Char('o')
220  && c[2] == QLatin1Char('n') && c[3] == QLatin1Char('g'))
222  else if (c[0] == QLatin1Char('c') && c[1] == QLatin1Char('h')
223  && c[2] == QLatin1Char('a') && c[3] == QLatin1Char('r'))
225  else if (c[0] == QLatin1Char('g') && c[1] == QLatin1Char('o')
226  && c[2] == QLatin1Char('t') && c[3] == QLatin1Char('o'))
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'))
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'))
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'))
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'))
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'))
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'))
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'))
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'))
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'))
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'))
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'))
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'))
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'))
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'))
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'))
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'))
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'))
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'))
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'))
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'))
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'))
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'))
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'))
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'))
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'))
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'))
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'))
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'))
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'))
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'))
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'))
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'))
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'))
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'))
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'))
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'))
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'))
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'))
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'))
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'))
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'))
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'))
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'))
461  }
462  } break;
463 
464  } // switch
465 
466  return -1;
467 }
468 
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);
498  } else if (current == '/' && next1 == '*') {
499  recordStartPos();
500  shift(1);
502  } else if (current == 0) {
505  // automatic semicolon insertion if program incomplete
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();
517  setDone(Other);
518  } else {
520  yylineno++;
521  yycolumn = 0;
522  bol = true;
523  terminator = true;
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) &&
540  shift(3);
542  } else {
543  setDone(Bad);
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);
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();
569  if (token != -1) {
573  // automatic semicolon insertion
574  stackToken = token;
576  }
577  setDone(Other);
578  }
579  else {
580  setDone(Bad);
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);
596  errmsg = QCoreApplication::translate("QDeclarativeParser", "Unclosed string at end of line");
597  } else if (current == '\\') {
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' &&
609  shift(2);
610  state = InString;
611  } else if (isOctalDigit(current) &&
612  isOctalDigit(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);
622  errmsg = QCoreApplication::translate("QDeclarativeParser", "Illegal escape sequence");
623  }
624  } else if (current == 'x')
625  state = InHexEscape;
626  else if (current == 'u')
628  else {
629  if (isLineTerminator()) {
631  yylineno++;
632  yycolumn = 0;
633  bol = true;
634  } else {
636  }
637  state = InString;
638  }
639  break;
640  case InHexEscape:
641  if (isHexDigit(current) && isHexDigit(next1)) {
642  state = InString;
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) &&
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);
668  errmsg = QCoreApplication::translate("QDeclarativeParser", "Illegal unicode escape sequence");
669  }
670  break;
671  case InSingleLineComment:
672  if (isLineTerminator()) {
674  yylineno++;
675  yycolumn = 0;
676  terminator = true;
677  bol = true;
678  if (restrKeyword) {
680  setDone(Other);
681  } else
682  state = Start;
684  } else if (current == 0) {
686  setDone(Eof);
687  }
688 
689  break;
690  case InMultiLineComment:
691  if (current == 0) {
692  setDone(Bad);
694  errmsg = QCoreApplication::translate("QDeclarativeParser", "Unclosed comment at end of file");
696  } else if (isLineTerminator()) {
698  yylineno++;
699  } else if (current == '*' && next1 == '/') {
700  state = Start;
701  shift(1);
703  }
704 
705  break;
706  case InIdentifier:
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) &&
717  shift(3);
718  break;
719  } else {
720  setDone(Bad);
722  errmsg = QCoreApplication::translate("QDeclarativeParser", "Illegal unicode escape sequence");
723  break;
724  }
725  }
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);
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);
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);
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);
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;
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) {
848  if (parenthesesCount == 0)
850  } else if (token == QDeclarativeJSGrammar::T_LPAREN) {
852  }
853  break;
854  case BalancedParentheses:
856  break;
857  }
858 
859  switch (state) {
860  case Eof:
861  return 0;
862  case Other:
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;
878  }
881  restrKeyword = true;
882  } else if (token == QDeclarativeJSGrammar::T_IF || token == QDeclarativeJSGrammar::T_FOR
885  parenthesesCount = 0;
886  } else if (token == QDeclarativeJSGrammar::T_DO) {
888  }
889  return token;
890  case String:
891  if (driver)
892  qsyylval.ustr = driver->intern(buffer16, pos16);
893  else
894  qsyylval.ustr = 0;
896  case Number:
897  qsyylval.dval = dval;
899  case Bad:
900  return -1;
901  default:
902  Q_ASSERT(!"unhandled numeration value in switch");
903  return -1;
904  }
905 }
906 
908 {
909  return (current == ' ' || current == '\t' ||
910  current == 0x0b || current == 0x0c);
911 }
912 
914 {
915  return (current == '\n' || current == '\r');
916 }
917 
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 
933 {
934  return (c >= '0' && c <= '9');
935 }
936 
938 {
939  return ((c >= '0' && c <= '9')
940  || (c >= 'a' && c <= 'f')
941  || (c >= 'A' && c <= 'F'));
942 }
943 
945 {
946  return (c >= '0' && c <= '7');
947 }
948 
950  ushort c3, ushort c4)
951 {
952  if (c1 == '>' && c2 == '>' && c3 == '>' && c4 == '=') {
953  shift(4);
955  } else if (c1 == '=' && c2 == '=' && c3 == '=') {
956  shift(3);
958  } else if (c1 == '!' && c2 == '=' && c3 == '=') {
959  shift(3);
961  } else if (c1 == '>' && c2 == '>' && c3 == '>') {
962  shift(3);
964  } else if (c1 == '<' && c2 == '<' && c3 == '=') {
965  shift(3);
967  } else if (c1 == '>' && c2 == '>' && c3 == '=') {
968  shift(3);
970  } else if (c1 == '<' && c2 == '=') {
971  shift(2);
973  } else if (c1 == '>' && c2 == '=') {
974  shift(2);
976  } else if (c1 == '!' && c2 == '=') {
977  shift(2);
979  } else if (c1 == '+' && c2 == '+') {
980  shift(2);
982  } else if (c1 == '-' && c2 == '-') {
983  shift(2);
985  } else if (c1 == '=' && c2 == '=') {
986  shift(2);
988  } else if (c1 == '+' && c2 == '=') {
989  shift(2);
991  } else if (c1 == '-' && c2 == '=') {
992  shift(2);
994  } else if (c1 == '*' && c2 == '=') {
995  shift(2);
997  } else if (c1 == '/' && c2 == '=') {
998  shift(2);
1000  } else if (c1 == '&' && c2 == '=') {
1001  shift(2);
1003  } else if (c1 == '^' && c2 == '=') {
1004  shift(2);
1006  } else if (c1 == '%' && c2 == '=') {
1007  shift(2);
1009  } else if (c1 == '|' && c2 == '=') {
1010  shift(2);
1012  } else if (c1 == '<' && c2 == '<') {
1013  shift(2);
1015  } else if (c1 == '>' && c2 == '>') {
1016  shift(2);
1018  } else if (c1 == '&' && c2 == '&') {
1019  shift(2);
1021  } else if (c1 == '|' && c2 == '|') {
1022  shift(2);
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 
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 
1083  ushort c3) const
1084 {
1085  return ((c1 - '0') * 64 + (c2 - '0') * 8 + c3 - '0');
1086 }
1087 
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 
1104  ushort c3, ushort c4)
1105 {
1106  return QChar((convertHex(c3) << 4) + convertHex(c4),
1107  (convertHex(c1) << 4) + convertHex(c2));
1108 }
1109 
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 
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 
1141 {
1142  startpos = pos;
1145 }
1146 
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
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 
1244 {
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)
1251  } else {
1253  }
1254 }
1255 
1257 
1258 
static unsigned char convertHex(ushort c1)
static bool isIdentLetter(ushort c)
Lexer(Engine *eng, bool tokenizeComments=false)
unsigned char c[8]
Definition: qnumeric_p.h:62
static int flagFromChar(const QChar &)
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
NameId * intern(const QChar *u, int s)
int length() const
Returns the number of characters in this string.
Definition: qstring.h:696
static bool isDecimalDigit(ushort c)
The QString class provides a Unicode character string.
Definition: qstring.h:83
Q_CORE_EXPORT double qstrtod(const char *s00, char const **se, bool *ok)
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
The QChar class provides a 16-bit Unicode character.
Definition: qchar.h:72
static QChar convertUnicode(ushort c1, ushort c2, ushort c3, ushort c4)
static QString translate(const char *context, const char *key, const char *disambiguation=0, Encoding encoding=CodecForTr)
bool scanRegExp(RegExpBodyPrefix prefix=NoPrefix)
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
#define shiftWindowsLineBreak()
int findReservedWord(const QChar *buffer, int size) const
const QChar * unicode() const
Returns a &#39;\0&#39;-terminated Unicode representation of the string.
Definition: qstring.h:706
#define QT_QML_END_NAMESPACE
unsigned int uint
Definition: qglobal.h:996
#define QT_QML_BEGIN_NAMESPACE
The State element defines configurations of objects and properties.
ushort singleEscape(ushort c) const
bool isHexDigit(ushort c) const
#define Q_ASSERT_X(cond, where, what)
Definition: qglobal.h:1837
QString arg(qlonglong a, int fieldwidth=0, int base=10, const QChar &fillChar=QLatin1Char(' ')) const Q_REQUIRED_RESULT
Definition: qstring.cpp:7186
#define Q_CORE_EXPORT
Definition: qglobal.h:1449
union QDeclarativeJS::Lexer::@103 qsyylval
void clear()
Clears the contents of the string and makes it empty.
Definition: qstring.h:723
unsigned short ushort
Definition: qglobal.h:995
ParenthesesState parenthesesState
ushort convertOctal(ushort c1, ushort c2, ushort c3) const
void addComment(int pos, int len, int line, int col)
int matchPunctuator(ushort c1, ushort c2, ushort c3, ushort c4)
double integerFromString(const char *buf, int size, int radix)
bool isOctalDigit(ushort c) const
The QLatin1Char class provides an 8-bit ASCII/Latin-1 character.
Definition: qchar.h:55
bool isLetterOrNumber() const
Returns true if the character is a letter or number (Letter_* or Number_* categories); otherwise retu...
Definition: qchar.cpp:681
void setCode(const QString &c, int lineno)