Whoops, fix last minute bug.
[WebKit-https.git] / Source / JavaScriptCore / parser / Lexer.cpp
1 /*
2  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All Rights Reserved.
4  *  Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
5  *  Copyright (C) 2010 Zoltan Herczeg (zherczeg@inf.u-szeged.hu)
6  *
7  *  This library is free software; you can redistribute it and/or
8  *  modify it under the terms of the GNU Library General Public
9  *  License as published by the Free Software Foundation; either
10  *  version 2 of the License, or (at your option) any later version.
11  *
12  *  This library is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  *  Library General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Library General Public License
18  *  along with this library; see the file COPYING.LIB.  If not, write to
19  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  *  Boston, MA 02110-1301, USA.
21  *
22  */
23
24 #include "config.h"
25 #include "Lexer.h"
26
27 #include "JSFunction.h"
28
29 #include "JSGlobalObjectFunctions.h"
30 #include "Identifier.h"
31 #include "NodeInfo.h"
32 #include "Nodes.h"
33 #include "dtoa.h"
34 #include <ctype.h>
35 #include <limits.h>
36 #include <string.h>
37 #include <wtf/Assertions.h>
38
39 using namespace WTF;
40 using namespace Unicode;
41
42 #include "JSParser.h"
43 #include "KeywordLookup.h"
44 #include "Lookup.h"
45 #include "Lexer.lut.h"
46
47 namespace JSC {
48
49
50 enum CharacterType {
51     // Types for the main switch
52
53     // The first three types are fixed, and also used for identifying
54     // ASCII alpha and alphanumeric characters (see isIdentStart and isIdentPart).
55     CharacterIdentifierStart,
56     CharacterZero,
57     CharacterNumber,
58
59     CharacterInvalid,
60     CharacterLineTerminator,
61     CharacterExclamationMark,
62     CharacterOpenParen,
63     CharacterCloseParen,
64     CharacterOpenBracket,
65     CharacterCloseBracket,
66     CharacterComma,
67     CharacterColon,
68     CharacterQuestion,
69     CharacterTilde,
70     CharacterQuote,
71     CharacterDot,
72     CharacterSlash,
73     CharacterBackSlash,
74     CharacterSemicolon,
75     CharacterOpenBrace,
76     CharacterCloseBrace,
77
78     CharacterAdd,
79     CharacterSub,
80     CharacterMultiply,
81     CharacterModulo,
82     CharacterAnd,
83     CharacterXor,
84     CharacterOr,
85     CharacterLess,
86     CharacterGreater,
87     CharacterEqual,
88
89     // Other types (only one so far)
90     CharacterWhiteSpace,
91 };
92
93 // 128 ASCII codes
94 static const unsigned short typesOfASCIICharacters[128] = {
95 /*   0 - Null               */ CharacterInvalid,
96 /*   1 - Start of Heading   */ CharacterInvalid,
97 /*   2 - Start of Text      */ CharacterInvalid,
98 /*   3 - End of Text        */ CharacterInvalid,
99 /*   4 - End of Transm.     */ CharacterInvalid,
100 /*   5 - Enquiry            */ CharacterInvalid,
101 /*   6 - Acknowledgment     */ CharacterInvalid,
102 /*   7 - Bell               */ CharacterInvalid,
103 /*   8 - Back Space         */ CharacterInvalid,
104 /*   9 - Horizontal Tab     */ CharacterWhiteSpace,
105 /*  10 - Line Feed          */ CharacterLineTerminator,
106 /*  11 - Vertical Tab       */ CharacterWhiteSpace,
107 /*  12 - Form Feed          */ CharacterWhiteSpace,
108 /*  13 - Carriage Return    */ CharacterLineTerminator,
109 /*  14 - Shift Out          */ CharacterInvalid,
110 /*  15 - Shift In           */ CharacterInvalid,
111 /*  16 - Data Line Escape   */ CharacterInvalid,
112 /*  17 - Device Control 1   */ CharacterInvalid,
113 /*  18 - Device Control 2   */ CharacterInvalid,
114 /*  19 - Device Control 3   */ CharacterInvalid,
115 /*  20 - Device Control 4   */ CharacterInvalid,
116 /*  21 - Negative Ack.      */ CharacterInvalid,
117 /*  22 - Synchronous Idle   */ CharacterInvalid,
118 /*  23 - End of Transmit    */ CharacterInvalid,
119 /*  24 - Cancel             */ CharacterInvalid,
120 /*  25 - End of Medium      */ CharacterInvalid,
121 /*  26 - Substitute         */ CharacterInvalid,
122 /*  27 - Escape             */ CharacterInvalid,
123 /*  28 - File Separator     */ CharacterInvalid,
124 /*  29 - Group Separator    */ CharacterInvalid,
125 /*  30 - Record Separator   */ CharacterInvalid,
126 /*  31 - Unit Separator     */ CharacterInvalid,
127 /*  32 - Space              */ CharacterWhiteSpace,
128 /*  33 - !                  */ CharacterExclamationMark,
129 /*  34 - "                  */ CharacterQuote,
130 /*  35 - #                  */ CharacterInvalid,
131 /*  36 - $                  */ CharacterIdentifierStart,
132 /*  37 - %                  */ CharacterModulo,
133 /*  38 - &                  */ CharacterAnd,
134 /*  39 - '                  */ CharacterQuote,
135 /*  40 - (                  */ CharacterOpenParen,
136 /*  41 - )                  */ CharacterCloseParen,
137 /*  42 - *                  */ CharacterMultiply,
138 /*  43 - +                  */ CharacterAdd,
139 /*  44 - ,                  */ CharacterComma,
140 /*  45 - -                  */ CharacterSub,
141 /*  46 - .                  */ CharacterDot,
142 /*  47 - /                  */ CharacterSlash,
143 /*  48 - 0                  */ CharacterZero,
144 /*  49 - 1                  */ CharacterNumber,
145 /*  50 - 2                  */ CharacterNumber,
146 /*  51 - 3                  */ CharacterNumber,
147 /*  52 - 4                  */ CharacterNumber,
148 /*  53 - 5                  */ CharacterNumber,
149 /*  54 - 6                  */ CharacterNumber,
150 /*  55 - 7                  */ CharacterNumber,
151 /*  56 - 8                  */ CharacterNumber,
152 /*  57 - 9                  */ CharacterNumber,
153 /*  58 - :                  */ CharacterColon,
154 /*  59 - ;                  */ CharacterSemicolon,
155 /*  60 - <                  */ CharacterLess,
156 /*  61 - =                  */ CharacterEqual,
157 /*  62 - >                  */ CharacterGreater,
158 /*  63 - ?                  */ CharacterQuestion,
159 /*  64 - @                  */ CharacterInvalid,
160 /*  65 - A                  */ CharacterIdentifierStart,
161 /*  66 - B                  */ CharacterIdentifierStart,
162 /*  67 - C                  */ CharacterIdentifierStart,
163 /*  68 - D                  */ CharacterIdentifierStart,
164 /*  69 - E                  */ CharacterIdentifierStart,
165 /*  70 - F                  */ CharacterIdentifierStart,
166 /*  71 - G                  */ CharacterIdentifierStart,
167 /*  72 - H                  */ CharacterIdentifierStart,
168 /*  73 - I                  */ CharacterIdentifierStart,
169 /*  74 - J                  */ CharacterIdentifierStart,
170 /*  75 - K                  */ CharacterIdentifierStart,
171 /*  76 - L                  */ CharacterIdentifierStart,
172 /*  77 - M                  */ CharacterIdentifierStart,
173 /*  78 - N                  */ CharacterIdentifierStart,
174 /*  79 - O                  */ CharacterIdentifierStart,
175 /*  80 - P                  */ CharacterIdentifierStart,
176 /*  81 - Q                  */ CharacterIdentifierStart,
177 /*  82 - R                  */ CharacterIdentifierStart,
178 /*  83 - S                  */ CharacterIdentifierStart,
179 /*  84 - T                  */ CharacterIdentifierStart,
180 /*  85 - U                  */ CharacterIdentifierStart,
181 /*  86 - V                  */ CharacterIdentifierStart,
182 /*  87 - W                  */ CharacterIdentifierStart,
183 /*  88 - X                  */ CharacterIdentifierStart,
184 /*  89 - Y                  */ CharacterIdentifierStart,
185 /*  90 - Z                  */ CharacterIdentifierStart,
186 /*  91 - [                  */ CharacterOpenBracket,
187 /*  92 - \                  */ CharacterBackSlash,
188 /*  93 - ]                  */ CharacterCloseBracket,
189 /*  94 - ^                  */ CharacterXor,
190 /*  95 - _                  */ CharacterIdentifierStart,
191 /*  96 - `                  */ CharacterInvalid,
192 /*  97 - a                  */ CharacterIdentifierStart,
193 /*  98 - b                  */ CharacterIdentifierStart,
194 /*  99 - c                  */ CharacterIdentifierStart,
195 /* 100 - d                  */ CharacterIdentifierStart,
196 /* 101 - e                  */ CharacterIdentifierStart,
197 /* 102 - f                  */ CharacterIdentifierStart,
198 /* 103 - g                  */ CharacterIdentifierStart,
199 /* 104 - h                  */ CharacterIdentifierStart,
200 /* 105 - i                  */ CharacterIdentifierStart,
201 /* 106 - j                  */ CharacterIdentifierStart,
202 /* 107 - k                  */ CharacterIdentifierStart,
203 /* 108 - l                  */ CharacterIdentifierStart,
204 /* 109 - m                  */ CharacterIdentifierStart,
205 /* 110 - n                  */ CharacterIdentifierStart,
206 /* 111 - o                  */ CharacterIdentifierStart,
207 /* 112 - p                  */ CharacterIdentifierStart,
208 /* 113 - q                  */ CharacterIdentifierStart,
209 /* 114 - r                  */ CharacterIdentifierStart,
210 /* 115 - s                  */ CharacterIdentifierStart,
211 /* 116 - t                  */ CharacterIdentifierStart,
212 /* 117 - u                  */ CharacterIdentifierStart,
213 /* 118 - v                  */ CharacterIdentifierStart,
214 /* 119 - w                  */ CharacterIdentifierStart,
215 /* 120 - x                  */ CharacterIdentifierStart,
216 /* 121 - y                  */ CharacterIdentifierStart,
217 /* 122 - z                  */ CharacterIdentifierStart,
218 /* 123 - {                  */ CharacterOpenBrace,
219 /* 124 - |                  */ CharacterOr,
220 /* 125 - }                  */ CharacterCloseBrace,
221 /* 126 - ~                  */ CharacterTilde,
222 /* 127 - Delete             */ CharacterInvalid,
223 };
224
225 Lexer::Lexer(JSGlobalData* globalData)
226     : m_isReparsing(false)
227     , m_globalData(globalData)
228     , m_keywordTable(JSC::mainTable)
229 {
230 }
231
232 Lexer::~Lexer()
233 {
234     m_keywordTable.deleteTable();
235 }
236
237 ALWAYS_INLINE const UChar* Lexer::currentCharacter() const
238 {
239     ASSERT(m_code <= m_codeEnd);
240     return m_code;
241 }
242
243 ALWAYS_INLINE int Lexer::currentOffset() const
244 {
245     return currentCharacter() - m_codeStart;
246 }
247
248 void Lexer::setCode(const SourceCode& source, ParserArena& arena)
249 {
250     m_arena = &arena.identifierArena();
251
252     m_lineNumber = source.firstLine();
253     m_delimited = false;
254     m_lastToken = -1;
255
256     const UChar* data = source.provider()->data();
257
258     m_source = &source;
259     m_codeStart = data;
260     m_code = data + source.startOffset();
261     m_codeEnd = data + source.endOffset();
262     m_error = false;
263     m_atLineStart = true;
264
265     m_buffer8.reserveInitialCapacity(initialReadBufferCapacity);
266     m_buffer16.reserveInitialCapacity((m_codeEnd - m_code) / 2);
267
268     if (LIKELY(m_code < m_codeEnd))
269         m_current = *m_code;
270     else
271         m_current = -1;
272     ASSERT(currentOffset() == source.startOffset());
273 }
274
275 template <int shiftAmount, Lexer::ShiftType shouldBoundsCheck> ALWAYS_INLINE void Lexer::internalShift()
276 {
277     if (shouldBoundsCheck == DoBoundsCheck) {
278         // Faster than an if-else sequence
279         ASSERT(m_current != -1);
280         m_current = -1;
281         m_code += shiftAmount;
282         if (LIKELY(m_code < m_codeEnd))
283             m_current = *m_code;
284     } else {
285         m_code += shiftAmount;
286         m_current = *m_code;
287     }
288 }
289
290 ALWAYS_INLINE void Lexer::shift()
291 {
292     internalShift<1, DoBoundsCheck>();
293 }
294
295 ALWAYS_INLINE int Lexer::peek(int offset)
296 {
297     // Only use if necessary
298     ASSERT(offset > 0 && offset < 5);
299     const UChar* code = m_code + offset;
300     return (code < m_codeEnd) ? *code : -1;
301 }
302
303 int Lexer::getUnicodeCharacter()
304 {
305     int char1 = peek(1);
306     int char2 = peek(2);
307     int char3 = peek(3);
308
309     if (UNLIKELY(!isASCIIHexDigit(m_current) || !isASCIIHexDigit(char1) || !isASCIIHexDigit(char2) || !isASCIIHexDigit(char3)))
310         return -1;
311
312     int result = convertUnicode(m_current, char1, char2, char3);
313     shift();
314     shift();
315     shift();
316     shift();
317     return result;
318 }
319
320 void Lexer::shiftLineTerminator()
321 {
322     ASSERT(isLineTerminator(m_current));
323
324     int m_prev = m_current;
325     shift();
326
327     // Allow both CRLF and LFCR.
328     if (m_prev + m_current == '\n' + '\r')
329         shift();
330
331     ++m_lineNumber;
332 }
333
334 ALWAYS_INLINE const Identifier* Lexer::makeIdentifier(const UChar* characters, size_t length)
335 {
336     return &m_arena->makeIdentifier(m_globalData, characters, length);
337 }
338
339 ALWAYS_INLINE bool Lexer::lastTokenWasRestrKeyword() const
340 {
341     return m_lastToken == CONTINUE || m_lastToken == BREAK || m_lastToken == RETURN || m_lastToken == THROW;
342 }
343
344 static NEVER_INLINE bool isNonASCIIIdentStart(int c)
345 {
346     return category(c) & (Letter_Uppercase | Letter_Lowercase | Letter_Titlecase | Letter_Modifier | Letter_Other);
347 }
348
349 static inline bool isIdentStart(int c)
350 {
351     return isASCII(c) ? typesOfASCIICharacters[c] == CharacterIdentifierStart : isNonASCIIIdentStart(c);
352 }
353
354 static NEVER_INLINE bool isNonASCIIIdentPart(int c)
355 {
356     return category(c) & (Letter_Uppercase | Letter_Lowercase | Letter_Titlecase | Letter_Modifier | Letter_Other
357         | Mark_NonSpacing | Mark_SpacingCombining | Number_DecimalDigit | Punctuation_Connector);
358 }
359
360 static inline bool isIdentPart(int c)
361 {
362     // Character types are divided into two groups depending on whether they can be part of an
363     // identifier or not. Those whose type value is less or equal than CharacterNumber can be
364     // part of an identifier. (See the CharacterType definition for more details.)
365     return isASCII(c) ? typesOfASCIICharacters[c] <= CharacterNumber : isNonASCIIIdentPart(c);
366 }
367
368 static inline int singleEscape(int c)
369 {
370     switch (c) {
371     case 'b':
372         return 0x08;
373     case 't':
374         return 0x09;
375     case 'n':
376         return 0x0A;
377     case 'v':
378         return 0x0B;
379     case 'f':
380         return 0x0C;
381     case 'r':
382         return 0x0D;
383     case '\\':
384         return '\\';
385     case '\'':
386         return '\'';
387     case '"':
388         return '"';
389     default:
390         return 0;
391     }
392 }
393
394 inline void Lexer::record8(int c)
395 {
396     ASSERT(c >= 0);
397     ASSERT(c <= 0xFF);
398     m_buffer8.append(static_cast<char>(c));
399 }
400
401 inline void Lexer::record16(UChar c)
402 {
403     m_buffer16.append(c);
404 }
405
406 inline void Lexer::record16(int c)
407 {
408     ASSERT(c >= 0);
409     ASSERT(c <= USHRT_MAX);
410     record16(UChar(static_cast<unsigned short>(c)));
411 }
412
413 template <bool shouldCreateIdentifier> ALWAYS_INLINE JSTokenType Lexer::parseIdentifier(JSTokenData* lvalp, unsigned lexType)
414 {
415     const ptrdiff_t remaining = m_codeEnd - m_code;
416     if ((remaining >= maxTokenLength) && !(lexType & IgnoreReservedWords)) {
417         JSTokenType keyword = parseKeyword();
418         if (keyword != IDENT)
419             return keyword;
420     }
421     const UChar* identifierStart = currentCharacter();
422     bool bufferRequired = false;
423
424     while (true) {
425         if (LIKELY(isIdentPart(m_current))) {
426             shift();
427             continue;
428         }
429         if (LIKELY(m_current != '\\'))
430             break;
431
432         // \uXXXX unicode characters.
433         bufferRequired = true;
434         if (identifierStart != currentCharacter())
435             m_buffer16.append(identifierStart, currentCharacter() - identifierStart);
436         shift();
437         if (UNLIKELY(m_current != 'u'))
438             return ERRORTOK;
439         shift();
440         int character = getUnicodeCharacter();
441         if (UNLIKELY(character == -1))
442             return ERRORTOK;
443         if (UNLIKELY(m_buffer16.size() ? !isIdentPart(character) : !isIdentStart(character)))
444             return ERRORTOK;
445         if  (shouldCreateIdentifier)
446             record16(character);
447         identifierStart = currentCharacter();
448     }
449     
450     int identifierLength;
451     const Identifier* ident = 0;
452     if (shouldCreateIdentifier) {
453         if (!bufferRequired)
454             identifierLength = currentCharacter() - identifierStart;
455         else {
456             if (identifierStart != currentCharacter())
457                 m_buffer16.append(identifierStart, currentCharacter() - identifierStart);
458             identifierStart = m_buffer16.data();
459             identifierLength = m_buffer16.size();
460         }
461
462         ident = makeIdentifier(identifierStart, identifierLength);
463         lvalp->ident = ident;
464     } else
465         lvalp->ident = 0;
466
467     m_delimited = false;
468
469     if (LIKELY(!bufferRequired && !(lexType & IgnoreReservedWords))) {
470         ASSERT(shouldCreateIdentifier);
471         // Keywords must not be recognized if there was an \uXXXX in the identifier.
472         if (remaining < maxTokenLength) {
473             const HashEntry* entry = m_keywordTable.entry(m_globalData, *ident);
474             ASSERT((remaining < maxTokenLength) || !entry);
475             return entry ? static_cast<JSTokenType>(entry->lexerValue()) : IDENT;
476         }
477         return IDENT;
478     }
479
480     m_buffer16.resize(0);
481     return IDENT;
482 }
483
484 template <bool shouldBuildStrings> ALWAYS_INLINE bool Lexer::parseString(JSTokenData* lvalp, bool strictMode)
485 {
486     int stringQuoteCharacter = m_current;
487     shift();
488
489     const UChar* stringStart = currentCharacter();
490
491     while (m_current != stringQuoteCharacter) {
492         if (UNLIKELY(m_current == '\\')) {
493             if (stringStart != currentCharacter() && shouldBuildStrings)
494                 m_buffer16.append(stringStart, currentCharacter() - stringStart);
495             shift();
496
497             int escape = singleEscape(m_current);
498
499             // Most common escape sequences first
500             if (escape) {
501                  if (shouldBuildStrings)
502                      record16(escape);
503                 shift();
504             } else if (UNLIKELY(isLineTerminator(m_current)))
505                 shiftLineTerminator();
506             else if (m_current == 'x') {
507                 shift();
508                 if (isASCIIHexDigit(m_current) && isASCIIHexDigit(peek(1))) {
509                     int prev = m_current;
510                     shift();
511                     if (shouldBuildStrings)
512                         record16(convertHex(prev, m_current));
513                     shift();
514                 } else if (shouldBuildStrings)
515                     record16('x');
516             } else if (m_current == 'u') {
517                 shift();
518                 int character = getUnicodeCharacter();
519                 if (character != -1) {
520                     if (shouldBuildStrings)
521                         record16(character);
522                 } else if (m_current == stringQuoteCharacter) {
523                     if (shouldBuildStrings)
524                         record16('u');
525                 } else // Only stringQuoteCharacter allowed after \u
526                     return false;
527             } else if (strictMode && isASCIIDigit(m_current)) {
528                 // The only valid numeric escape in strict mode is '\0', and this must not be followed by a decimal digit.
529                 int character1 = m_current;
530                 shift();
531                 if (character1 != '0' || isASCIIDigit(m_current))
532                     return false;
533                 if (shouldBuildStrings)
534                     record16(0);
535             } else if (!strictMode && isASCIIOctalDigit(m_current)) {
536                 // Octal character sequences
537                 int character1 = m_current;
538                 shift();
539                 if (isASCIIOctalDigit(m_current)) {
540                     // Two octal characters
541                     int character2 = m_current;
542                     shift();
543                     if (character1 >= '0' && character1 <= '3' && isASCIIOctalDigit(m_current)) {
544                         if (shouldBuildStrings)
545                             record16((character1 - '0') * 64 + (character2 - '0') * 8 + m_current - '0');
546                         shift();
547                     } else {
548                         if (shouldBuildStrings)
549                             record16((character1 - '0') * 8 + character2 - '0');
550                     }
551                 } else {
552                     if (shouldBuildStrings)
553                         record16(character1 - '0');
554                 }
555             } else if (m_current != -1) {
556                 if (shouldBuildStrings)
557                     record16(m_current);
558                 shift();
559             } else
560                 return false;
561
562             stringStart = currentCharacter();
563             continue;
564         }
565         // Fast check for characters that require special handling.
566         // Catches -1, \n, \r, 0x2028, and 0x2029 as efficiently
567         // as possible, and lets through all common ASCII characters.
568         if (UNLIKELY(((static_cast<unsigned>(m_current) - 0xE) & 0x2000))) {
569             // New-line or end of input is not allowed
570             if (UNLIKELY(isLineTerminator(m_current)) || UNLIKELY(m_current == -1))
571                 return false;
572             // Anything else is just a normal character
573         }
574         shift();
575     }
576
577     if (currentCharacter() != stringStart && shouldBuildStrings)
578         m_buffer16.append(stringStart, currentCharacter() - stringStart);
579     if (shouldBuildStrings)
580         lvalp->ident = makeIdentifier(m_buffer16.data(), m_buffer16.size());
581     else
582         lvalp->ident = 0;
583
584     m_buffer16.resize(0);
585     return true;
586 }
587
588 ALWAYS_INLINE void Lexer::parseHex(double& returnValue)
589 {
590     // Optimization: most hexadecimal values fit into 4 bytes.
591     uint32_t hexValue = 0;
592     int maximumDigits = 7;
593
594     // Shift out the 'x' prefix.
595     shift();
596
597     do {
598         hexValue = (hexValue << 4) + toASCIIHexValue(m_current);
599         shift();
600         --maximumDigits;
601     } while (isASCIIHexDigit(m_current) && maximumDigits >= 0);
602
603     if (maximumDigits >= 0) {
604         returnValue = hexValue;
605         return;
606     }
607
608     // No more place in the hexValue buffer.
609     // The values are shifted out and placed into the m_buffer8 vector.
610     for (int i = 0; i < 8; ++i) {
611          int digit = hexValue >> 28;
612          if (digit < 10)
613              record8(digit + '0');
614          else
615              record8(digit - 10 + 'a');
616          hexValue <<= 4;
617     }
618
619     while (isASCIIHexDigit(m_current)) {
620         record8(m_current);
621         shift();
622     }
623
624     returnValue = parseIntOverflow(m_buffer8.data(), m_buffer8.size(), 16);
625 }
626
627 ALWAYS_INLINE bool Lexer::parseOctal(double& returnValue)
628 {
629     // Optimization: most octal values fit into 4 bytes.
630     uint32_t octalValue = 0;
631     int maximumDigits = 9;
632     // Temporary buffer for the digits. Makes easier
633     // to reconstruct the input characters when needed.
634     char digits[10];
635
636     do {
637         octalValue = octalValue * 8 + (m_current - '0');
638         digits[maximumDigits] = m_current;
639         shift();
640         --maximumDigits;
641     } while (isASCIIOctalDigit(m_current) && maximumDigits >= 0);
642
643     if (!isASCIIDigit(m_current) && maximumDigits >= 0) {
644         returnValue = octalValue;
645         return true;
646     }
647
648     for (int i = 9; i > maximumDigits; --i)
649          record8(digits[i]);
650
651     while (isASCIIOctalDigit(m_current)) {
652         record8(m_current);
653         shift();
654     }
655
656     if (isASCIIDigit(m_current))
657         return false;
658
659     returnValue = parseIntOverflow(m_buffer8.data(), m_buffer8.size(), 8);
660     return true;
661 }
662
663 ALWAYS_INLINE bool Lexer::parseDecimal(double& returnValue)
664 {
665     // Optimization: most decimal values fit into 4 bytes.
666     uint32_t decimalValue = 0;
667
668     // Since parseOctal may be executed before parseDecimal,
669     // the m_buffer8 may hold ascii digits.
670     if (!m_buffer8.size()) {
671         int maximumDigits = 9;
672         // Temporary buffer for the digits. Makes easier
673         // to reconstruct the input characters when needed.
674         char digits[10];
675
676         do {
677             decimalValue = decimalValue * 10 + (m_current - '0');
678             digits[maximumDigits] = m_current;
679             shift();
680             --maximumDigits;
681         } while (isASCIIDigit(m_current) && maximumDigits >= 0);
682
683         if (maximumDigits >= 0 && m_current != '.' && (m_current | 0x20) != 'e') {
684             returnValue = decimalValue;
685             return true;
686         }
687
688         for (int i = 9; i > maximumDigits; --i)
689             record8(digits[i]);
690     }
691
692     while (isASCIIDigit(m_current)) {
693         record8(m_current);
694         shift();
695     }
696
697     return false;
698 }
699
700 ALWAYS_INLINE void Lexer::parseNumberAfterDecimalPoint()
701 {
702     record8('.');
703     while (isASCIIDigit(m_current)) {
704         record8(m_current);
705         shift();
706     }
707 }
708
709 ALWAYS_INLINE bool Lexer::parseNumberAfterExponentIndicator()
710 {
711     record8('e');
712     shift();
713     if (m_current == '+' || m_current == '-') {
714         record8(m_current);
715         shift();
716     }
717
718     if (!isASCIIDigit(m_current))
719         return false;
720
721     do {
722         record8(m_current);
723         shift();
724     } while (isASCIIDigit(m_current));
725     return true;
726 }
727
728 ALWAYS_INLINE bool Lexer::parseMultilineComment()
729 {
730     while (true) {
731         while (UNLIKELY(m_current == '*')) {
732             shift();
733             if (m_current == '/') {
734                 shift();
735                 return true;
736             }
737         }
738
739         if (UNLIKELY(m_current == -1))
740             return false;
741
742         if (isLineTerminator(m_current))
743             shiftLineTerminator();
744         else
745             shift();
746     }
747 }
748
749 bool Lexer::nextTokenIsColon()
750 {
751     const UChar* code = m_code;
752     while (code < m_codeEnd && (isWhiteSpace(*code) || isLineTerminator(*code)))
753         code++;
754         
755     return code < m_codeEnd && *code == ':';
756 }
757
758 JSTokenType Lexer::lex(JSTokenData* lvalp, JSTokenInfo* llocp, unsigned lexType, bool strictMode)
759 {
760     ASSERT(!m_error);
761     ASSERT(m_buffer8.isEmpty());
762     ASSERT(m_buffer16.isEmpty());
763
764     JSTokenType token = ERRORTOK;
765     m_terminator = false;
766
767 start:
768     while (isWhiteSpace(m_current))
769         shift();
770
771     int startOffset = currentOffset();
772
773     if (UNLIKELY(m_current == -1))
774         return EOFTOK;
775
776     m_delimited = false;
777
778     CharacterType type;
779     if (LIKELY(isASCII(m_current)))
780         type = static_cast<CharacterType>(typesOfASCIICharacters[m_current]);
781     else if (isNonASCIIIdentStart(m_current))
782         type = CharacterIdentifierStart;
783     else if (isLineTerminator(m_current))
784         type = CharacterLineTerminator;
785     else
786         type = CharacterInvalid;
787
788     switch (type) {
789     case CharacterGreater:
790         shift();
791         if (m_current == '>') {
792             shift();
793             if (m_current == '>') {
794                 shift();
795                 if (m_current == '=') {
796                     shift();
797                     token = URSHIFTEQUAL;
798                     break;
799                 }
800                 token = URSHIFT;
801                 break;
802             }
803             if (m_current == '=') {
804                 shift();
805                 token = RSHIFTEQUAL;
806                 break;
807             }
808             token = RSHIFT;
809             break;
810         }
811         if (m_current == '=') {
812             shift();
813             token = GE;
814             break;
815         }
816         token = GT;
817         break;
818     case CharacterEqual:
819         shift();
820         if (m_current == '=') {
821             shift();
822             if (m_current == '=') {
823                 shift();
824                 token = STREQ;
825                 break;
826             }
827             token = EQEQ;
828             break;
829         }
830         token = EQUAL;
831         break;
832     case CharacterLess:
833         shift();
834         if (m_current == '!' && peek(1) == '-' && peek(2) == '-') {
835             // <!-- marks the beginning of a line comment (for www usage)
836             goto inSingleLineComment;
837         }
838         if (m_current == '<') {
839             shift();
840             if (m_current == '=') {
841                 shift();
842                 token = LSHIFTEQUAL;
843                 break;
844             }
845             token = LSHIFT;
846             break;
847         }
848         if (m_current == '=') {
849             shift();
850             token = LE;
851             break;
852         }
853         token = LT;
854         break;
855     case CharacterExclamationMark:
856         shift();
857         if (m_current == '=') {
858             shift();
859             if (m_current == '=') {
860                 shift();
861                 token = STRNEQ;
862                 break;
863             }
864             token = NE;
865             break;
866         }
867         token = EXCLAMATION;
868         break;
869     case CharacterAdd:
870         shift();
871         if (m_current == '+') {
872             shift();
873             token = (!m_terminator) ? PLUSPLUS : AUTOPLUSPLUS;
874             break;
875         }
876         if (m_current == '=') {
877             shift();
878             token = PLUSEQUAL;
879             break;
880         }
881         token = PLUS;
882         break;
883     case CharacterSub:
884         shift();
885         if (m_current == '-') {
886             shift();
887             if (m_atLineStart && m_current == '>') {
888                 shift();
889                 goto inSingleLineComment;
890             }
891             token = (!m_terminator) ? MINUSMINUS : AUTOMINUSMINUS;
892             break;
893         }
894         if (m_current == '=') {
895             shift();
896             token = MINUSEQUAL;
897             break;
898         }
899         token = MINUS;
900         break;
901     case CharacterMultiply:
902         shift();
903         if (m_current == '=') {
904             shift();
905             token = MULTEQUAL;
906             break;
907         }
908         token = TIMES;
909         break;
910     case CharacterSlash:
911         shift();
912         if (m_current == '/') {
913             shift();
914             goto inSingleLineComment;
915         }
916         if (m_current == '*') {
917             shift();
918             if (parseMultilineComment())
919                 goto start;
920             goto returnError;
921         }
922         if (m_current == '=') {
923             shift();
924             token = DIVEQUAL;
925             break;
926         }
927         token = DIVIDE;
928         break;
929     case CharacterAnd:
930         shift();
931         if (m_current == '&') {
932             shift();
933             token = AND;
934             break;
935         }
936         if (m_current == '=') {
937             shift();
938             token = ANDEQUAL;
939             break;
940         }
941         token = BITAND;
942         break;
943     case CharacterXor:
944         shift();
945         if (m_current == '=') {
946             shift();
947             token = XOREQUAL;
948             break;
949         }
950         token = BITXOR;
951         break;
952     case CharacterModulo:
953         shift();
954         if (m_current == '=') {
955             shift();
956             token = MODEQUAL;
957             break;
958         }
959         token = MOD;
960         break;
961     case CharacterOr:
962         shift();
963         if (m_current == '=') {
964             shift();
965             token = OREQUAL;
966             break;
967         }
968         if (m_current == '|') {
969             shift();
970             token = OR;
971             break;
972         }
973         token = BITOR;
974         break;
975     case CharacterOpenParen:
976         token = OPENPAREN;
977         shift();
978         break;
979     case CharacterCloseParen:
980         token = CLOSEPAREN;
981         shift();
982         break;
983     case CharacterOpenBracket:
984         token = OPENBRACKET;
985         shift();
986         break;
987     case CharacterCloseBracket:
988         token = CLOSEBRACKET;
989         shift();
990         break;
991     case CharacterComma:
992         token = COMMA;
993         shift();
994         break;
995     case CharacterColon:
996         token = COLON;
997         shift();
998         break;
999     case CharacterQuestion:
1000         token = QUESTION;
1001         shift();
1002         break;
1003     case CharacterTilde:
1004         token = TILDE;
1005         shift();
1006         break;
1007     case CharacterSemicolon:
1008         m_delimited = true;
1009         shift();
1010         token = SEMICOLON;
1011         break;
1012     case CharacterOpenBrace:
1013         lvalp->intValue = currentOffset();
1014         shift();
1015         token = OPENBRACE;
1016         break;
1017     case CharacterCloseBrace:
1018         lvalp->intValue = currentOffset();
1019         m_delimited = true;
1020         shift();
1021         token = CLOSEBRACE;
1022         break;
1023     case CharacterDot:
1024         shift();
1025         if (!isASCIIDigit(m_current)) {
1026             token = DOT;
1027             break;
1028         }
1029         goto inNumberAfterDecimalPoint;
1030     case CharacterZero:
1031         shift();
1032         if ((m_current | 0x20) == 'x' && isASCIIHexDigit(peek(1))) {
1033             parseHex(lvalp->doubleValue);
1034             token = NUMBER;
1035         } else {
1036             record8('0');
1037             if (isASCIIOctalDigit(m_current)) {
1038                 if (parseOctal(lvalp->doubleValue)) {
1039                     if (strictMode)
1040                         goto returnError;
1041                     token = NUMBER;
1042                 }
1043             }
1044         }
1045         // Fall through into CharacterNumber
1046     case CharacterNumber:
1047         if (LIKELY(token != NUMBER)) {
1048             if (!parseDecimal(lvalp->doubleValue)) {
1049                 if (m_current == '.') {
1050                     shift();
1051 inNumberAfterDecimalPoint:
1052                     parseNumberAfterDecimalPoint();
1053                 }
1054                 if ((m_current | 0x20) == 'e')
1055                     if (!parseNumberAfterExponentIndicator())
1056                         goto returnError;
1057                 // Null-terminate string for strtod.
1058                 m_buffer8.append('\0');
1059                 lvalp->doubleValue = WTF::strtod(m_buffer8.data(), 0);
1060             }
1061             token = NUMBER;
1062         }
1063
1064         // No identifiers allowed directly after numeric literal, e.g. "3in" is bad.
1065         if (UNLIKELY(isIdentStart(m_current)))
1066             goto returnError;
1067         m_buffer8.resize(0);
1068         m_delimited = false;
1069         break;
1070     case CharacterQuote:
1071         if (lexType & DontBuildStrings) {
1072             if (UNLIKELY(!parseString<false>(lvalp, strictMode)))
1073                 goto returnError;
1074         } else {
1075             if (UNLIKELY(!parseString<true>(lvalp, strictMode)))
1076                 goto returnError;
1077         }
1078         shift();
1079         m_delimited = false;
1080         token = STRING;
1081         break;
1082     case CharacterIdentifierStart:
1083         ASSERT(isIdentStart(m_current));
1084         // Fall through into CharacterBackSlash.
1085     case CharacterBackSlash:
1086         if (lexType & DontBuildKeywords)
1087             token = parseIdentifier<false>(lvalp, lexType);
1088         else
1089             token = parseIdentifier<true>(lvalp, lexType);
1090         break;
1091     case CharacterLineTerminator:
1092         ASSERT(isLineTerminator(m_current));
1093         shiftLineTerminator();
1094         m_atLineStart = true;
1095         m_terminator = true;
1096         goto start;
1097     case CharacterInvalid:
1098         goto returnError;
1099     default:
1100         ASSERT_NOT_REACHED();
1101         goto returnError;
1102     }
1103
1104     m_atLineStart = false;
1105     goto returnToken;
1106
1107 inSingleLineComment:
1108     while (!isLineTerminator(m_current)) {
1109         if (UNLIKELY(m_current == -1))
1110             return EOFTOK;
1111         shift();
1112     }
1113     shiftLineTerminator();
1114     m_atLineStart = true;
1115     m_terminator = true;
1116     if (!lastTokenWasRestrKeyword())
1117         goto start;
1118
1119     token = SEMICOLON;
1120     m_delimited = true;
1121     // Fall through into returnToken.
1122
1123 returnToken:
1124     llocp->line = m_lineNumber;
1125     llocp->startOffset = startOffset;
1126     llocp->endOffset = currentOffset();
1127     m_lastToken = token;
1128     return token;
1129
1130 returnError:
1131     m_error = true;
1132     return ERRORTOK;
1133 }
1134
1135 bool Lexer::scanRegExp(const Identifier*& pattern, const Identifier*& flags, UChar patternPrefix)
1136 {
1137     ASSERT(m_buffer16.isEmpty());
1138
1139     bool lastWasEscape = false;
1140     bool inBrackets = false;
1141
1142     if (patternPrefix) {
1143         ASSERT(!isLineTerminator(patternPrefix));
1144         ASSERT(patternPrefix != '/');
1145         ASSERT(patternPrefix != '[');
1146         record16(patternPrefix);
1147     }
1148
1149     while (true) {
1150         int current = m_current;
1151
1152         if (isLineTerminator(current) || current == -1) {
1153             m_buffer16.resize(0);
1154             return false;
1155         }
1156
1157         shift();
1158
1159         if (current == '/' && !lastWasEscape && !inBrackets)
1160             break;
1161
1162         record16(current);
1163
1164         if (lastWasEscape) {
1165             lastWasEscape = false;
1166             continue;
1167         }
1168
1169         switch (current) {
1170         case '[':
1171             inBrackets = true;
1172             break;
1173         case ']':
1174             inBrackets = false;
1175             break;
1176         case '\\':
1177             lastWasEscape = true;
1178             break;
1179         }
1180     }
1181
1182     pattern = makeIdentifier(m_buffer16.data(), m_buffer16.size());
1183     m_buffer16.resize(0);
1184
1185     while (isIdentPart(m_current)) {
1186         record16(m_current);
1187         shift();
1188     }
1189
1190     flags = makeIdentifier(m_buffer16.data(), m_buffer16.size());
1191     m_buffer16.resize(0);
1192
1193     return true;
1194 }
1195
1196 bool Lexer::skipRegExp()
1197 {
1198     bool lastWasEscape = false;
1199     bool inBrackets = false;
1200
1201     while (true) {
1202         int current = m_current;
1203
1204         if (isLineTerminator(current) || current == -1)
1205             return false;
1206
1207         shift();
1208
1209         if (current == '/' && !lastWasEscape && !inBrackets)
1210             break;
1211
1212         if (lastWasEscape) {
1213             lastWasEscape = false;
1214             continue;
1215         }
1216
1217         switch (current) {
1218         case '[':
1219             inBrackets = true;
1220             break;
1221         case ']':
1222             inBrackets = false;
1223             break;
1224         case '\\':
1225             lastWasEscape = true;
1226             break;
1227         }
1228     }
1229
1230     while (isIdentPart(m_current))
1231         shift();
1232
1233     return true;
1234 }
1235
1236 void Lexer::clear()
1237 {
1238     m_arena = 0;
1239
1240     Vector<char> newBuffer8;
1241     m_buffer8.swap(newBuffer8);
1242
1243     Vector<UChar> newBuffer16;
1244     m_buffer16.swap(newBuffer16);
1245
1246     m_isReparsing = false;
1247 }
1248
1249 SourceCode Lexer::sourceCode(int openBrace, int closeBrace, int firstLine)
1250 {
1251     ASSERT(m_source->provider()->data()[openBrace] == '{');
1252     ASSERT(m_source->provider()->data()[closeBrace] == '}');
1253     return SourceCode(m_source->provider(), openBrace, closeBrace + 1, firstLine);
1254 }
1255
1256 } // namespace JSC