e904ff6a37ccabaad6dc2cfadc74cecd5064ea73
[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 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qdeclarativejslexer_p.h"
43 #include "qdeclarativejsengine_p.h"
44 #include "qdeclarativejsmemorypool_p.h"
45
46 #include <private/qdeclarativeutils_p.h>
47 #include <QtCore/QCoreApplication>
48 #include <QtCore/QVarLengthArray>
49 #include <QtCore/QDebug>
50
51 QT_BEGIN_NAMESPACE
52 Q_CORE_EXPORT double qstrtod(const char *s00, char const **se, bool *ok);
53 QT_END_NAMESPACE
54
55 using namespace QDeclarativeJS;
56
57 enum RegExpFlag {
58     Global     = 0x01,
59     IgnoreCase = 0x02,
60     Multiline  = 0x04
61 };
62
63 static int flagFromChar(const QChar &ch)
64 {
65     switch (ch.unicode()) {
66     case 'g': return Global;
67     case 'i': return IgnoreCase;
68     case 'm': return Multiline;
69     }
70     return 0;
71 }
72
73 static unsigned char convertHex(ushort c)
74 {
75     if (c >= '0' && c <= '9')
76         return (c - '0');
77     else if (c >= 'a' && c <= 'f')
78         return (c - 'a' + 10);
79     else
80         return (c - 'A' + 10);
81 }
82
83 static unsigned char convertHex(QChar c1, QChar c2)
84 {
85     return ((convertHex(c1.unicode()) << 4) + convertHex(c2.unicode()));
86 }
87
88 static QChar convertUnicode(QChar c1, QChar c2, QChar c3, QChar c4)
89 {
90     return QChar((convertHex(c3.unicode()) << 4) + convertHex(c4.unicode()),
91                  (convertHex(c1.unicode()) << 4) + convertHex(c2.unicode()));
92 }
93
94 Lexer::Lexer(Engine *engine)
95     : _engine(engine)
96     , _codePtr(0)
97     , _lastLinePtr(0)
98     , _tokenLinePtr(0)
99     , _tokenStartPtr(0)
100     , _char(QLatin1Char('\n'))
101     , _errorCode(NoError)
102     , _currentLineNumber(0)
103     , _tokenValue(0)
104     , _parenthesesState(IgnoreParentheses)
105     , _parenthesesCount(0)
106     , _stackToken(-1)
107     , _patternFlags(0)
108     , _tokenLength(0)
109     , _tokenLine(0)
110     , _validTokenText(false)
111     , _prohibitAutomaticSemicolon(false)
112     , _restrictedKeyword(false)
113     , _terminator(false)
114     , _delimited(false)
115 {
116     if (engine)
117         engine->setLexer(this);
118 }
119
120 QString Lexer::code() const
121 {
122     return _code;
123 }
124
125 void Lexer::setCode(const QString &code, int lineno)
126 {
127     if (_engine)
128         _engine->setCode(code);
129
130     _code = code;
131     _tokenText.clear();
132     _tokenText.reserve(1024);
133     _errorMessage.clear();
134     _tokenSpell = QStringRef();
135
136     _codePtr = code.unicode();
137     _lastLinePtr = _codePtr;
138     _tokenLinePtr = _codePtr;
139     _tokenStartPtr = _codePtr;
140
141     _char = QLatin1Char('\n');
142     _errorCode = NoError;
143
144     _currentLineNumber = lineno;
145     _tokenValue = 0;
146
147     // parentheses state
148     _parenthesesState = IgnoreParentheses;
149     _parenthesesCount = 0;
150
151     _stackToken = -1;
152
153     _patternFlags = 0;
154     _tokenLength = 0;
155     _tokenLine = lineno;
156
157     _validTokenText = false;
158     _prohibitAutomaticSemicolon = false;
159     _restrictedKeyword = false;
160     _terminator = false;
161     _delimited = false;
162 }
163
164 void Lexer::scanChar()
165 {
166     _char = *_codePtr++;
167
168     if (_char == QLatin1Char('\n')) {
169         _lastLinePtr = _codePtr; // points to the first character after the newline
170         ++_currentLineNumber;
171     }
172 }
173
174 int Lexer::lex()
175 {
176     _tokenSpell = QStringRef();
177     int token = scanToken();
178     _tokenLength = _codePtr - _tokenStartPtr - 1;
179
180     _delimited = false;
181     _restrictedKeyword = false;
182
183     // update the flags
184     switch (token) {
185     case T_LBRACE:
186     case T_SEMICOLON:
187         _delimited = true;
188         break;
189
190     case T_IF:
191     case T_FOR:
192     case T_WHILE:
193     case T_WITH:
194         _parenthesesState = CountParentheses;
195         _parenthesesCount = 0;
196         break;
197
198     case T_DO:
199         _parenthesesState = BalancedParentheses;
200         break;
201
202     case T_CONTINUE:
203     case T_BREAK:
204     case T_RETURN:
205     case T_THROW:
206         _restrictedKeyword = true;
207         break;
208     } // switch
209
210     // update the parentheses state
211     switch (_parenthesesState) {
212     case IgnoreParentheses:
213         break;
214
215     case CountParentheses:
216         if (token == T_RPAREN) {
217             --_parenthesesCount;
218             if (_parenthesesCount == 0)
219                 _parenthesesState = BalancedParentheses;
220         } else if (token == T_LPAREN) {
221             ++_parenthesesCount;
222         }
223         break;
224
225     case BalancedParentheses:
226         _parenthesesState = IgnoreParentheses;
227         break;
228     } // switch
229
230     return token;
231 }
232
233 bool Lexer::isUnicodeEscapeSequence(const QChar *chars)
234 {
235     if (isHexDigit(chars[0]) && isHexDigit(chars[1]) && isHexDigit(chars[2]) && isHexDigit(chars[3]))
236         return true;
237
238     return false;
239 }
240
241 QChar Lexer::decodeUnicodeEscapeCharacter(bool *ok)
242 {
243     if (_char == QLatin1Char('u') && isUnicodeEscapeSequence(&_codePtr[0])) {
244         scanChar(); // skip u
245
246         const QChar c1 = _char;
247         scanChar();
248
249         const QChar c2 = _char;
250         scanChar();
251
252         const QChar c3 = _char;
253         scanChar();
254
255         const QChar c4 = _char;
256         scanChar();
257
258         if (ok)
259             *ok = true;
260
261         return convertUnicode(c1, c2, c3, c4);
262     }
263
264     *ok = false;
265     return QChar();
266 }
267
268 int Lexer::scanToken()
269 {
270     if (_stackToken != -1) {
271         int tk = _stackToken;
272         _stackToken = -1;
273         return tk;
274     }
275
276     _terminator = false;
277
278 again:
279     _validTokenText = false;
280     _tokenLinePtr = _lastLinePtr;
281
282     while (QDeclarativeUtils::isSpace(_char)) {
283         if (_char == QLatin1Char('\n')) {
284             _tokenLinePtr = _codePtr;
285
286             if (_restrictedKeyword) {
287                 // automatic semicolon insertion
288                 _tokenLine = _currentLineNumber;
289                 _tokenStartPtr = _codePtr - 1; // ### TODO: insert it before the optional \r sequence.
290                 return T_SEMICOLON;
291             } else {
292                 _terminator = true;
293                 syncProhibitAutomaticSemicolon();
294             }
295         }
296
297         scanChar();
298     }
299
300     _tokenStartPtr = _codePtr - 1;
301     _tokenLine = _currentLineNumber;
302
303     if (_char.isNull())
304         return EOF_SYMBOL;
305
306     const QChar ch = _char;
307     scanChar();
308
309     switch (ch.unicode()) {
310     case '~': return T_TILDE;
311     case '}': return T_RBRACE;
312
313     case '|':
314         if (_char == QLatin1Char('|')) {
315             scanChar();
316             return T_OR_OR;
317         } else if (_char == QLatin1Char('=')) {
318             scanChar();
319             return T_OR_EQ;
320         }
321         return T_OR;
322
323     case '{': return T_LBRACE;
324
325     case '^':
326         if (_char == QLatin1Char('=')) {
327             scanChar();
328             return T_XOR_EQ;
329         }
330         return T_XOR;
331
332     case ']': return T_RBRACKET;
333     case '[': return T_LBRACKET;
334     case '?': return T_QUESTION;
335
336     case '>':
337         if (_char == QLatin1Char('>')) {
338             scanChar();
339             if (_char == QLatin1Char('>')) {
340                 scanChar();
341                 if (_char == QLatin1Char('=')) {
342                     scanChar();
343                     return T_GT_GT_GT_EQ;
344                 }
345                 return T_GT_GT_GT;
346             } else if (_char == QLatin1Char('=')) {
347                 scanChar();
348                 return T_GT_GT_EQ;
349             }
350             return T_GT_GT;
351         } else if (_char == QLatin1Char('=')) {
352             scanChar();
353             return T_GE;
354         }
355         return T_GT;
356
357     case '=':
358         if (_char == QLatin1Char('=')) {
359             scanChar();
360             if (_char == QLatin1Char('=')) {
361                 scanChar();
362                 return T_EQ_EQ_EQ;
363             }
364             return T_EQ_EQ;
365         }
366         return T_EQ;
367
368     case '<':
369         if (_char == QLatin1Char('=')) {
370             scanChar();
371             return T_LE;
372         } else if (_char == QLatin1Char('<')) {
373             scanChar();
374             if (_char == QLatin1Char('=')) {
375                 scanChar();
376                 return T_LT_LT_EQ;
377             }
378             return T_LT_LT;
379         }
380         return T_LT;
381
382     case ';': return T_SEMICOLON;
383     case ':': return T_COLON;
384
385     case '/':
386         if (_char == QLatin1Char('*')) {
387             scanChar();
388             while (!_char.isNull()) {
389                 if (_char == QLatin1Char('*')) {
390                     scanChar();
391                     if (_char == QLatin1Char('/')) {
392                         scanChar();
393                         goto again;
394                     }
395                 } else {
396                     scanChar();
397                 }
398             }
399         } else if (_char == QLatin1Char('/')) {
400             while (!_char.isNull() && _char != QLatin1Char('\n')) {
401                 scanChar();
402             }
403             goto again;
404         } if (_char == QLatin1Char('=')) {
405             scanChar();
406             return T_DIVIDE_EQ;
407         }
408         return T_DIVIDE_;
409
410     case '.':
411         if (QDeclarativeUtils::isDigit(_char)) {
412             QVarLengthArray<char,32> chars;
413
414             chars.append(ch.unicode()); // append the `.'
415
416             while (QDeclarativeUtils::isDigit(_char)) {
417                 chars.append(_char.unicode());
418                 scanChar();
419             }
420
421             if (_char == QLatin1Char('e') || _char == QLatin1Char('E')) {
422                 if (QDeclarativeUtils::isDigit(_codePtr[0]) || ((_codePtr[0] == QLatin1Char('+') || _codePtr[0] == QLatin1Char('-')) &&
423                                               QDeclarativeUtils::isDigit(_codePtr[1]))) {
424
425                     chars.append(_char.unicode());
426                     scanChar(); // consume `e'
427
428                     if (_char == QLatin1Char('+') || _char == QLatin1Char('-')) {
429                         chars.append(_char.unicode());
430                         scanChar(); // consume the sign
431                     }
432
433                     while (QDeclarativeUtils::isDigit(_char)) {
434                         chars.append(_char.unicode());
435                         scanChar();
436                     }
437                 }
438             }
439
440             chars.append('\0');
441
442             const char *begin = chars.constData();
443             const char *end = 0;
444             bool ok = false;
445
446             _tokenValue = qstrtod(begin, &end, &ok);
447
448             if (end - begin != chars.size() - 1) {
449                 _errorCode = IllegalExponentIndicator;
450                 _errorMessage = QCoreApplication::translate("QDeclarativeParser", "Illegal syntax for exponential number");
451                 return T_ERROR;
452             }
453
454             return T_NUMERIC_LITERAL;
455         }
456         return T_DOT;
457
458     case '-':
459         if (_char == QLatin1Char('=')) {
460             scanChar();
461             return T_MINUS_EQ;
462         } else if (_char == QLatin1Char('-')) {
463             scanChar();
464
465             if (_terminator && !_delimited && !_prohibitAutomaticSemicolon) {
466                 _stackToken = T_PLUS_PLUS;
467                 return T_SEMICOLON;
468             }
469
470             return T_MINUS_MINUS;
471         }
472         return T_MINUS;
473
474     case ',': return T_COMMA;
475
476     case '+':
477         if (_char == QLatin1Char('=')) {
478             scanChar();
479             return T_PLUS_EQ;
480         } else if (_char == QLatin1Char('+')) {
481             scanChar();
482
483             if (_terminator && !_delimited && !_prohibitAutomaticSemicolon) {
484                 _stackToken = T_PLUS_PLUS;
485                 return T_SEMICOLON;
486             }
487
488             return T_PLUS_PLUS;
489         }
490         return T_PLUS;
491
492     case '*':
493         if (_char == QLatin1Char('=')) {
494             scanChar();
495             return T_STAR_EQ;
496         }
497         return T_STAR;
498
499     case ')': return T_RPAREN;
500     case '(': return T_LPAREN;
501
502     case '&':
503         if (_char == QLatin1Char('=')) {
504             scanChar();
505             return T_AND_EQ;
506         } else if (_char == QLatin1Char('&')) {
507             scanChar();
508             return T_AND_AND;
509         }
510         return T_AND;
511
512     case '%':
513         if (_char == QLatin1Char('=')) {
514             scanChar();
515             return T_REMAINDER_EQ;
516         }
517         return T_REMAINDER;
518
519     case '!':
520         if (_char == QLatin1Char('=')) {
521             scanChar();
522             if (_char == QLatin1Char('=')) {
523                 scanChar();
524                 return T_NOT_EQ_EQ;
525             }
526             return T_NOT_EQ;
527         }
528         return T_NOT;
529
530     case '\'':
531     case '"': {
532         const QChar quote = ch;
533         _validTokenText = true;
534
535         bool multilineStringLiteral = false;
536
537         const QChar *startCode = _codePtr;
538
539         while (!_char.isNull()) {
540             if (_char == QLatin1Char('\n') || _char == QLatin1Char('\\')) {
541                 break;
542             } else if (_char == quote) {
543                 _tokenSpell = _engine->midRef(startCode - _code.unicode() - 1, _codePtr - startCode);
544                 scanChar();
545
546                 return T_STRING_LITERAL;
547             }
548             scanChar();
549         }
550
551         _tokenText.resize(0);
552         startCode--;
553         while (startCode != _codePtr - 1) 
554             _tokenText += *startCode++;
555
556         while (! _char.isNull()) {
557             if (_char == QLatin1Char('\n')) {
558                 multilineStringLiteral = true;
559                 _tokenText += _char;
560                 scanChar();
561             } else if (_char == quote) {
562                 scanChar();
563
564                 if (_engine)
565                     _tokenSpell = _engine->newStringRef(_tokenText);
566
567                 return multilineStringLiteral ? T_MULTILINE_STRING_LITERAL : T_STRING_LITERAL;
568             } else if (_char == QLatin1Char('\\')) {
569                 scanChar();
570
571                 QChar u;
572                 bool ok = false;
573
574                 switch (_char.unicode()) {
575                 // unicode escape sequence
576                 case 'u':
577                     u = decodeUnicodeEscapeCharacter(&ok);
578                     if (! ok)
579                         u = _char;
580                     break;
581
582                 // hex escape sequence
583                 case 'x':
584                 case 'X':
585                     if (isHexDigit(_codePtr[0]) && isHexDigit(_codePtr[1])) {
586                         scanChar();
587
588                         const QChar c1 = _char;
589                         scanChar();
590
591                         const QChar c2 = _char;
592                         scanChar();
593
594                         u = convertHex(c1, c2);
595                     } else {
596                         u = _char;
597                     }
598                     break;
599
600                 // single character escape sequence
601                 case '\\': u = QLatin1Char('\''); scanChar(); break;
602                 case '\'': u = QLatin1Char('\''); scanChar(); break;
603                 case '\"': u = QLatin1Char('\"'); scanChar(); break;
604                 case 'b':  u = QLatin1Char('\b'); scanChar(); break;
605                 case 'f':  u = QLatin1Char('\f'); scanChar(); break;
606                 case 'n':  u = QLatin1Char('\n'); scanChar(); break;
607                 case 'r':  u = QLatin1Char('\r'); scanChar(); break;
608                 case 't':  u = QLatin1Char('\t'); scanChar(); break;
609                 case 'v':  u = QLatin1Char('\v'); scanChar(); break;
610
611                 case '0':
612                     if (! _codePtr[1].isDigit()) {
613                         scanChar();
614                         u = QLatin1Char('\0');
615                     } else {
616                         // ### parse deprecated octal escape sequence ?
617                         u = _char;
618                     }
619                     break;
620
621                 case '\r':
622                     while (_char == QLatin1Char('\r'))
623                         scanChar();
624
625                     if (_char == '\n') {
626                         u = _char;
627                         scanChar();
628                     } else {
629                         u = QLatin1Char('\n');
630                     }
631
632                     break;
633
634                 case '\n':
635                     u = _char;
636                     scanChar();
637                     break;
638
639                 default:
640                     // non escape character
641                     u = _char;
642                     scanChar();
643                 }
644
645                 _tokenText += u;
646             } else {
647                 _tokenText += _char;
648                 scanChar();
649             }
650         }
651
652         _errorCode = UnclosedStringLiteral;
653         _errorMessage = QCoreApplication::translate("QDeclarativeParser", "Unclosed string at end of line");
654         return T_ERROR;
655     }
656
657     default:
658         if (QDeclarativeUtils::isLetter(ch) || ch == QLatin1Char('$') || ch == QLatin1Char('_') || (ch == QLatin1Char('\\') && _char == QLatin1Char('u'))) {
659             bool identifierWithEscapeChars = false;
660             if (ch == QLatin1Char('\\')) {
661                 identifierWithEscapeChars = true;
662                 _tokenText.resize(0);
663                 bool ok = false;
664                 _tokenText += decodeUnicodeEscapeCharacter(&ok);
665                 _validTokenText = true;
666                 if (! ok) {
667                     _errorCode = IllegalUnicodeEscapeSequence;
668                     _errorMessage = QCoreApplication::translate("QDeclarativeParser", "Illegal unicode escape sequence");
669                     return T_ERROR;
670                 }
671             }
672             while (true) {
673                 if (QDeclarativeUtils::isLetterOrNumber(_char) || _char == QLatin1Char('$') || _char == QLatin1Char('_')) {
674                     if (identifierWithEscapeChars)
675                         _tokenText += _char;
676
677                     scanChar();
678                 } else if (_char == QLatin1Char('\\') && _codePtr[0] == QLatin1Char('u')) {
679                     if (! identifierWithEscapeChars) {
680                         identifierWithEscapeChars = true;
681                         _tokenText.resize(0);
682                         _tokenText.insert(0, _tokenStartPtr, _codePtr - _tokenStartPtr - 1);
683                         _validTokenText = true;
684                     }
685
686                     scanChar(); // skip '\\'
687                     bool ok = false;
688                     _tokenText += decodeUnicodeEscapeCharacter(&ok);
689                     if (! ok) {
690                         _errorCode = IllegalUnicodeEscapeSequence;
691                         _errorMessage = QCoreApplication::translate("QDeclarativeParser", "Illegal unicode escape sequence");
692                         return T_ERROR;
693                     }
694                 } else {
695                     _tokenLength = _codePtr - _tokenStartPtr - 1;
696
697                     int kind = T_IDENTIFIER;
698
699                     if (! identifierWithEscapeChars)
700                         kind = classify(_tokenStartPtr, _tokenLength);
701
702                     if (_engine) {
703                         if (kind == T_IDENTIFIER && identifierWithEscapeChars)
704                             _tokenSpell = _engine->newStringRef(_tokenText);
705                         else
706                             _tokenSpell = _engine->midRef(_tokenStartPtr - _code.unicode(), _tokenLength);
707                     }
708
709                     return kind;
710                 }
711             }
712         } else if (QDeclarativeUtils::isDigit(ch)) {
713             if (ch != '0') {
714                 int integer = ch.unicode() - '0';
715
716                 QChar n = _char;
717                 const QChar *code = _codePtr;
718                 while (QDeclarativeUtils::isDigit(n)) {
719                     integer = integer * 10 + (n.unicode() - '0');
720                     n = *code++;
721                 }
722
723                 if (n != QLatin1Char('.') && n != QLatin1Char('e') && n != QLatin1Char('E')) {
724                     _codePtr = code - 1;
725                     scanChar();
726                     _tokenValue = integer;
727                     return T_NUMERIC_LITERAL;
728                 } 
729             }
730
731             QVarLengthArray<char,32> chars;
732             chars.append(ch.unicode());
733
734             if (ch == QLatin1Char('0') && (_char == 'x' || _char == 'X')) {
735                 // parse hex integer literal
736
737                 chars.append(_char.unicode());
738                 scanChar(); // consume `x'
739
740                 while (isHexDigit(_char)) {
741                     chars.append(_char.unicode());
742                     scanChar();
743                 }
744
745                 _tokenValue = integerFromString(chars.constData(), chars.size(), 16);
746                 return T_NUMERIC_LITERAL;
747             }
748
749             // decimal integer literal
750             while (QDeclarativeUtils::isDigit(_char)) {
751                 chars.append(_char.unicode());
752                 scanChar(); // consume the digit
753             }
754
755             if (_char == QLatin1Char('.')) {
756                 chars.append(_char.unicode());
757                 scanChar(); // consume `.'
758
759                 while (QDeclarativeUtils::isDigit(_char)) {
760                     chars.append(_char.unicode());
761                     scanChar();
762                 }
763
764                 if (_char == QLatin1Char('e') || _char == QLatin1Char('E')) {
765                     if (QDeclarativeUtils::isDigit(_codePtr[0]) || ((_codePtr[0] == QLatin1Char('+') || _codePtr[0] == QLatin1Char('-')) &&
766                                                   QDeclarativeUtils::isDigit(_codePtr[1]))) {
767
768                         chars.append(_char.unicode());
769                         scanChar(); // consume `e'
770
771                         if (_char == QLatin1Char('+') || _char == QLatin1Char('-')) {
772                             chars.append(_char.unicode());
773                             scanChar(); // consume the sign
774                         }
775
776                         while (QDeclarativeUtils::isDigit(_char)) {
777                             chars.append(_char.unicode());
778                             scanChar();
779                         }
780                     }
781                 }
782             } else if (_char == QLatin1Char('e') || _char == QLatin1Char('E')) {
783                 if (QDeclarativeUtils::isDigit(_codePtr[0]) || ((_codePtr[0] == QLatin1Char('+') || _codePtr[0] == QLatin1Char('-')) &&
784                                               QDeclarativeUtils::isDigit(_codePtr[1]))) {
785
786                     chars.append(_char.unicode());
787                     scanChar(); // consume `e'
788
789                     if (_char == QLatin1Char('+') || _char == QLatin1Char('-')) {
790                         chars.append(_char.unicode());
791                         scanChar(); // consume the sign
792                     }
793
794                     while (QDeclarativeUtils::isDigit(_char)) {
795                         chars.append(_char.unicode());
796                         scanChar();
797                     }
798                 }
799             }
800
801             chars.append('\0');
802
803             const char *begin = chars.constData();
804             const char *end = 0;
805             bool ok = false;
806
807             _tokenValue = qstrtod(begin, &end, &ok);
808
809             if (end - begin != chars.size() - 1) {
810                 _errorCode = IllegalExponentIndicator;
811                 _errorMessage = QCoreApplication::translate("QDeclarativeParser", "Illegal syntax for exponential number");
812                 return T_ERROR;
813             }
814
815             return T_NUMERIC_LITERAL;
816         }
817
818         break;
819     }
820
821     return T_ERROR;
822 }
823
824 bool Lexer::scanRegExp(RegExpBodyPrefix prefix)
825 {
826     _tokenText.resize(0);
827     _validTokenText = true;
828     _patternFlags = 0;
829
830     if (prefix == EqualPrefix)
831         _tokenText += QLatin1Char('=');
832
833     while (true) {
834         switch (_char.unicode()) {
835         case 0: // eof
836         case '\n': case '\r': // line terminator
837             _errorMessage = QCoreApplication::translate("QDeclarativeParser", "Unterminated regular expression literal");
838             return false;
839
840         case '/':
841             scanChar();
842
843             // scan the flags
844             _patternFlags = 0;
845             while (isIdentLetter(_char)) {
846                 int flag = flagFromChar(_char);
847                 if (flag == 0) {
848                     _errorMessage = QCoreApplication::translate("QDeclarativeParser", "Invalid regular expression flag '%0'")
849                              .arg(QChar(_char));
850                     return false;
851                 }
852                 _patternFlags |= flag;
853                 scanChar();
854             }
855             return true;
856
857         case '\\':
858             // regular expression backslash sequence
859             _tokenText += _char;
860             scanChar();
861
862             if (_char.isNull() || isLineTerminator()) {
863                 _errorMessage = QCoreApplication::translate("QDeclarativeParser", "Unterminated regular expression backslash sequence");
864                 return false;
865             }
866
867             _tokenText += _char;
868             scanChar();
869             break;
870
871         case '[':
872             // regular expression class
873             _tokenText += _char;
874             scanChar();
875
876             while (! _char.isNull() && ! isLineTerminator()) {
877                 if (_char == QLatin1Char(']'))
878                     break;
879                 else if (_char == QLatin1Char('\\')) {
880                     // regular expression backslash sequence
881                     _tokenText += _char;
882                     scanChar();
883
884                     if (_char.isNull() || isLineTerminator()) {
885                         _errorMessage = QCoreApplication::translate("QDeclarativeParser", "Unterminated regular expression backslash sequence");
886                         return false;
887                     }
888
889                     _tokenText += _char;
890                     scanChar();
891                 } else {
892                     _tokenText += _char;
893                     scanChar();
894                 }
895             }
896
897             if (_char != QLatin1Char(']')) {
898                 _errorMessage = QCoreApplication::translate("QDeclarativeParser", "Unterminated regular expression class");
899                 return false;
900             }
901
902             _tokenText += _char;
903             scanChar(); // skip ]
904             break;
905
906         default:
907             _tokenText += _char;
908             scanChar();
909         } // switch
910     } // while
911
912     return false;
913 }
914
915 bool Lexer::isLineTerminator() const
916 {
917     return (_char == QLatin1Char('\n') || _char == QLatin1Char('\r'));
918 }
919
920 bool Lexer::isIdentLetter(QChar ch)
921 {
922     // ASCII-biased, since all reserved words are ASCII, aand hence the
923     // bulk of content to be parsed.
924     if ((ch >= QLatin1Char('a') && ch <= QLatin1Char('z'))
925             || (ch >= QLatin1Char('A') && ch <= QLatin1Char('Z'))
926             || ch == QLatin1Char('$')
927             || ch == QLatin1Char('_'))
928         return true;
929     if (ch.unicode() < 128)
930         return false;
931     return ch.isLetterOrNumber();
932 }
933
934 bool Lexer::isDecimalDigit(ushort c)
935 {
936     return (c >= '0' && c <= '9');
937 }
938
939 bool Lexer::isHexDigit(QChar c)
940 {
941     return ((c >= QLatin1Char('0') && c <= QLatin1Char('9'))
942             || (c >= QLatin1Char('a') && c <= QLatin1Char('f'))
943             || (c >= QLatin1Char('A') && c <= QLatin1Char('F')));
944 }
945
946 bool Lexer::isOctalDigit(ushort c)
947 {
948     return (c >= '0' && c <= '7');
949 }
950
951 int Lexer::tokenOffset() const
952 {
953     return _tokenStartPtr - _code.unicode();
954 }
955
956 int Lexer::tokenLength() const
957 {
958     return _tokenLength;
959 }
960
961 int Lexer::tokenStartLine() const
962 {
963     return _tokenLine;
964 }
965
966 int Lexer::tokenStartColumn() const
967 {
968     return _tokenStartPtr - _tokenLinePtr + 1;
969 }
970
971 int Lexer::tokenEndLine() const
972 {
973     return _currentLineNumber;
974 }
975
976 int Lexer::tokenEndColumn() const
977 {
978     return _codePtr - _lastLinePtr;
979 }
980
981 QStringRef Lexer::tokenSpell() const
982 {
983     return _tokenSpell;
984 }
985
986 double Lexer::tokenValue() const
987 {
988     return _tokenValue;
989 }
990
991 QString Lexer::tokenText() const
992 {
993     if (_validTokenText)
994         return _tokenText;
995
996     return QString(_tokenStartPtr, _tokenLength);
997 }
998
999 Lexer::Error Lexer::errorCode() const
1000 {
1001     return _errorCode;
1002 }
1003
1004 QString Lexer::errorMessage() const
1005 {
1006     return _errorMessage;
1007 }
1008
1009 void Lexer::syncProhibitAutomaticSemicolon()
1010 {
1011     if (_parenthesesState == BalancedParentheses) {
1012         // we have seen something like "if (foo)", which means we should
1013         // never insert an automatic semicolon at this point, since it would
1014         // then be expanded into an empty statement (ECMA-262 7.9.1)
1015         _prohibitAutomaticSemicolon = true;
1016         _parenthesesState = IgnoreParentheses;
1017     } else {
1018         _prohibitAutomaticSemicolon = false;
1019     }
1020 }
1021
1022 bool Lexer::prevTerminator() const
1023 {
1024     return _terminator;
1025 }
1026
1027 #include "qdeclarativejskeywords_p.h"