2011-07-01 Juan C. Montemayor <jmont@apple.com>
[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 UString Lexer::getInvalidCharMessage()
238 {
239     switch (m_current) {
240     case 0:
241         return "Invalid character: '\\0'";
242     case 10:
243         return "Invalid character: '\\n'";
244     case 11:
245         return "Invalid character: '\\v'";
246     case 13:
247         return "Invalid character: '\\r'";
248     case 35:
249         return "Invalid character: '#'";
250     case 64:
251         return "Invalid character: '@'";
252     case 96:
253         return "Invalid character: '`'";
254     default:
255         return String::format("Invalid character '\\u%04u'", m_current).impl();
256     }
257 }
258
259 ALWAYS_INLINE const UChar* Lexer::currentCharacter() const
260 {
261     ASSERT(m_code <= m_codeEnd);
262     return m_code;
263 }
264
265 ALWAYS_INLINE int Lexer::currentOffset() const
266 {
267     return currentCharacter() - m_codeStart;
268 }
269
270 void Lexer::setCode(const SourceCode& source, ParserArena& arena)
271 {
272     m_arena = &arena.identifierArena();
273
274     m_lineNumber = source.firstLine();
275     m_delimited = false;
276     m_lastToken = -1;
277
278     const UChar* data = source.provider()->data();
279
280     m_source = &source;
281     m_codeStart = data;
282     m_code = data + source.startOffset();
283     m_codeEnd = data + source.endOffset();
284     m_error = false;
285     m_atLineStart = true;
286     m_lexErrorMessage = UString();
287
288     m_buffer8.reserveInitialCapacity(initialReadBufferCapacity);
289     m_buffer16.reserveInitialCapacity((m_codeEnd - m_code) / 2);
290
291     if (LIKELY(m_code < m_codeEnd))
292         m_current = *m_code;
293     else
294         m_current = -1;
295     ASSERT(currentOffset() == source.startOffset());
296 }
297
298 template <int shiftAmount, Lexer::ShiftType shouldBoundsCheck> ALWAYS_INLINE void Lexer::internalShift()
299 {
300     if (shouldBoundsCheck == DoBoundsCheck) {
301         // Faster than an if-else sequence
302         ASSERT(m_current != -1);
303         m_current = -1;
304         m_code += shiftAmount;
305         if (LIKELY(m_code < m_codeEnd))
306             m_current = *m_code;
307     } else {
308         m_code += shiftAmount;
309         m_current = *m_code;
310     }
311 }
312
313 ALWAYS_INLINE void Lexer::shift()
314 {
315     internalShift<1, DoBoundsCheck>();
316 }
317
318 ALWAYS_INLINE int Lexer::peek(int offset)
319 {
320     // Only use if necessary
321     ASSERT(offset > 0 && offset < 5);
322     const UChar* code = m_code + offset;
323     return (code < m_codeEnd) ? *code : -1;
324 }
325
326 int Lexer::getUnicodeCharacter()
327 {
328     int char1 = peek(1);
329     int char2 = peek(2);
330     int char3 = peek(3);
331
332     if (UNLIKELY(!isASCIIHexDigit(m_current) || !isASCIIHexDigit(char1) || !isASCIIHexDigit(char2) || !isASCIIHexDigit(char3)))
333         return -1;
334
335     int result = convertUnicode(m_current, char1, char2, char3);
336     shift();
337     shift();
338     shift();
339     shift();
340     return result;
341 }
342
343 void Lexer::shiftLineTerminator()
344 {
345     ASSERT(isLineTerminator(m_current));
346
347     int m_prev = m_current;
348     shift();
349
350     // Allow both CRLF and LFCR.
351     if (m_prev + m_current == '\n' + '\r')
352         shift();
353
354     ++m_lineNumber;
355 }
356
357 ALWAYS_INLINE bool Lexer::lastTokenWasRestrKeyword() const
358 {
359     return m_lastToken == CONTINUE || m_lastToken == BREAK || m_lastToken == RETURN || m_lastToken == THROW;
360 }
361
362 static NEVER_INLINE bool isNonASCIIIdentStart(int c)
363 {
364     return category(c) & (Letter_Uppercase | Letter_Lowercase | Letter_Titlecase | Letter_Modifier | Letter_Other);
365 }
366
367 static inline bool isIdentStart(int c)
368 {
369     return isASCII(c) ? typesOfASCIICharacters[c] == CharacterIdentifierStart : isNonASCIIIdentStart(c);
370 }
371
372 static NEVER_INLINE bool isNonASCIIIdentPart(int c)
373 {
374     return category(c) & (Letter_Uppercase | Letter_Lowercase | Letter_Titlecase | Letter_Modifier | Letter_Other
375         | Mark_NonSpacing | Mark_SpacingCombining | Number_DecimalDigit | Punctuation_Connector);
376 }
377
378 static ALWAYS_INLINE bool isIdentPart(int c)
379 {
380     // Character types are divided into two groups depending on whether they can be part of an
381     // identifier or not. Those whose type value is less or equal than CharacterNumber can be
382     // part of an identifier. (See the CharacterType definition for more details.)
383     return isASCII(c) ? typesOfASCIICharacters[c] <= CharacterNumber : isNonASCIIIdentPart(c);
384 }
385
386 static inline int singleEscape(int c)
387 {
388     switch (c) {
389     case 'b':
390         return 0x08;
391     case 't':
392         return 0x09;
393     case 'n':
394         return 0x0A;
395     case 'v':
396         return 0x0B;
397     case 'f':
398         return 0x0C;
399     case 'r':
400         return 0x0D;
401     case '\\':
402         return '\\';
403     case '\'':
404         return '\'';
405     case '"':
406         return '"';
407     default:
408         return 0;
409     }
410 }
411
412 inline void Lexer::record8(int c)
413 {
414     ASSERT(c >= 0);
415     ASSERT(c <= 0xFF);
416     m_buffer8.append(static_cast<char>(c));
417 }
418
419 inline void Lexer::record16(UChar c)
420 {
421     m_buffer16.append(c);
422 }
423
424 inline void Lexer::record16(int c)
425 {
426     ASSERT(c >= 0);
427     ASSERT(c <= USHRT_MAX);
428     record16(UChar(static_cast<unsigned short>(c)));
429 }
430
431 template <bool shouldCreateIdentifier> ALWAYS_INLINE JSTokenType Lexer::parseIdentifier(JSTokenData* tokenData, unsigned lexType, bool strictMode)
432 {
433     const ptrdiff_t remaining = m_codeEnd - m_code;
434     if ((remaining >= maxTokenLength) && !(lexType & IgnoreReservedWords)) {
435         JSTokenType keyword = parseKeyword<shouldCreateIdentifier>(tokenData);
436         if (keyword != IDENT && (keyword != RESERVED_IF_STRICT || strictMode)) {
437             ASSERT((!shouldCreateIdentifier) || tokenData->ident);
438             return keyword;
439         }
440     }
441     const UChar* identifierStart = currentCharacter();
442     bool bufferRequired = false;
443
444     while (true) {
445         if (LIKELY(isIdentPart(m_current))) {
446             shift();
447             continue;
448         }
449         if (LIKELY(m_current != '\\'))
450             break;
451
452         // \uXXXX unicode characters.
453         bufferRequired = true;
454         if (identifierStart != currentCharacter())
455             m_buffer16.append(identifierStart, currentCharacter() - identifierStart);
456         shift();
457         if (UNLIKELY(m_current != 'u'))
458             return ERRORTOK;
459         shift();
460         int character = getUnicodeCharacter();
461         if (UNLIKELY(character == -1))
462             return ERRORTOK;
463         if (UNLIKELY(m_buffer16.size() ? !isIdentPart(character) : !isIdentStart(character)))
464             return ERRORTOK;
465         if  (shouldCreateIdentifier)
466             record16(character);
467         identifierStart = currentCharacter();
468     }
469     
470     int identifierLength;
471     const Identifier* ident = 0;
472     if (shouldCreateIdentifier) {
473         if (!bufferRequired)
474             identifierLength = currentCharacter() - identifierStart;
475         else {
476             if (identifierStart != currentCharacter())
477                 m_buffer16.append(identifierStart, currentCharacter() - identifierStart);
478             identifierStart = m_buffer16.data();
479             identifierLength = m_buffer16.size();
480         }
481
482         ident = makeIdentifier(identifierStart, identifierLength);
483         tokenData->ident = ident;
484     } else
485         tokenData->ident = 0;
486
487     m_delimited = false;
488
489     if (LIKELY(!bufferRequired && !(lexType & IgnoreReservedWords))) {
490         ASSERT(shouldCreateIdentifier);
491         // Keywords must not be recognized if there was an \uXXXX in the identifier.
492         if (remaining < maxTokenLength) {
493             const HashEntry* entry = m_keywordTable.entry(m_globalData, *ident);
494             ASSERT((remaining < maxTokenLength) || !entry);
495             if (!entry)
496                 return IDENT;
497             JSTokenType token = static_cast<JSTokenType>(entry->lexerValue());
498             return (token != RESERVED_IF_STRICT) || strictMode ? token : IDENT;
499         }
500         return IDENT;
501     }
502
503     m_buffer16.resize(0);
504     return IDENT;
505 }
506
507 bool Lexer::isKeyword(const Identifier& ident)
508 {
509     return m_keywordTable.entry(m_globalData, ident);
510 }
511
512 template <bool shouldBuildStrings> ALWAYS_INLINE bool Lexer::parseString(JSTokenData* tokenData, bool strictMode)
513 {
514     int stringQuoteCharacter = m_current;
515     shift();
516
517     const UChar* stringStart = currentCharacter();
518
519     while (m_current != stringQuoteCharacter) {
520         if (UNLIKELY(m_current == '\\')) {
521             if (stringStart != currentCharacter() && shouldBuildStrings)
522                 m_buffer16.append(stringStart, currentCharacter() - stringStart);
523             shift();
524
525             int escape = singleEscape(m_current);
526
527             // Most common escape sequences first
528             if (escape) {
529                  if (shouldBuildStrings)
530                      record16(escape);
531                 shift();
532             } else if (UNLIKELY(isLineTerminator(m_current)))
533                 shiftLineTerminator();
534             else if (m_current == 'x') {
535                 shift();
536                 if (isASCIIHexDigit(m_current) && isASCIIHexDigit(peek(1))) {
537                     int prev = m_current;
538                     shift();
539                     if (shouldBuildStrings)
540                         record16(convertHex(prev, m_current));
541                     shift();
542                 } else if (shouldBuildStrings)
543                     record16('x');
544             } else if (m_current == 'u') {
545                 shift();
546                 int character = getUnicodeCharacter();
547                 if (character != -1) {
548                     if (shouldBuildStrings)
549                         record16(character);
550                 } else if (m_current == stringQuoteCharacter) {
551                     if (shouldBuildStrings)
552                         record16('u');
553                 } else {
554                     m_lexErrorMessage = "\\u can only be followed by a Unicode character sequence";
555                     return false;
556                 }
557             } else if (strictMode && isASCIIDigit(m_current)) {
558                 // The only valid numeric escape in strict mode is '\0', and this must not be followed by a decimal digit.
559                 int character1 = m_current;
560                 shift();
561                 if (character1 != '0' || isASCIIDigit(m_current)) {
562                     m_lexErrorMessage = "The only valid numeric escape in strict mode is '\\0'";
563                     return false;
564                 }
565                 if (shouldBuildStrings)
566                     record16(0);
567             } else if (!strictMode && isASCIIOctalDigit(m_current)) {
568                 // Octal character sequences
569                 int character1 = m_current;
570                 shift();
571                 if (isASCIIOctalDigit(m_current)) {
572                     // Two octal characters
573                     int character2 = m_current;
574                     shift();
575                     if (character1 >= '0' && character1 <= '3' && isASCIIOctalDigit(m_current)) {
576                         if (shouldBuildStrings)
577                             record16((character1 - '0') * 64 + (character2 - '0') * 8 + m_current - '0');
578                         shift();
579                     } else {
580                         if (shouldBuildStrings)
581                             record16((character1 - '0') * 8 + character2 - '0');
582                     }
583                 } else {
584                     if (shouldBuildStrings)
585                         record16(character1 - '0');
586                 }
587             } else if (m_current != -1) {
588                 if (shouldBuildStrings)
589                     record16(m_current);
590                 shift();
591             } else {
592                 m_lexErrorMessage = "Unterminated string constant";
593                 return false;
594             }
595
596             stringStart = currentCharacter();
597             continue;
598         }
599         // Fast check for characters that require special handling.
600         // Catches -1, \n, \r, 0x2028, and 0x2029 as efficiently
601         // as possible, and lets through all common ASCII characters.
602         if (UNLIKELY(((static_cast<unsigned>(m_current) - 0xE) & 0x2000))) {
603             // New-line or end of input is not allowed
604             if (UNLIKELY(isLineTerminator(m_current)) || UNLIKELY(m_current == -1)) {
605                 m_lexErrorMessage = "Unexpected EOF";
606                 return false;
607             }
608             // Anything else is just a normal character
609         }
610         shift();
611     }
612
613     if (currentCharacter() != stringStart && shouldBuildStrings)
614         m_buffer16.append(stringStart, currentCharacter() - stringStart);
615     if (shouldBuildStrings)
616         tokenData->ident = makeIdentifier(m_buffer16.data(), m_buffer16.size());
617     else
618         tokenData->ident = 0;
619
620     m_buffer16.resize(0);
621     return true;
622 }
623
624 ALWAYS_INLINE void Lexer::parseHex(double& returnValue)
625 {
626     // Optimization: most hexadecimal values fit into 4 bytes.
627     uint32_t hexValue = 0;
628     int maximumDigits = 7;
629
630     // Shift out the 'x' prefix.
631     shift();
632
633     do {
634         hexValue = (hexValue << 4) + toASCIIHexValue(m_current);
635         shift();
636         --maximumDigits;
637     } while (isASCIIHexDigit(m_current) && maximumDigits >= 0);
638
639     if (maximumDigits >= 0) {
640         returnValue = hexValue;
641         return;
642     }
643
644     // No more place in the hexValue buffer.
645     // The values are shifted out and placed into the m_buffer8 vector.
646     for (int i = 0; i < 8; ++i) {
647          int digit = hexValue >> 28;
648          if (digit < 10)
649              record8(digit + '0');
650          else
651              record8(digit - 10 + 'a');
652          hexValue <<= 4;
653     }
654
655     while (isASCIIHexDigit(m_current)) {
656         record8(m_current);
657         shift();
658     }
659
660     returnValue = parseIntOverflow(m_buffer8.data(), m_buffer8.size(), 16);
661 }
662
663 ALWAYS_INLINE bool Lexer::parseOctal(double& returnValue)
664 {
665     // Optimization: most octal values fit into 4 bytes.
666     uint32_t octalValue = 0;
667     int maximumDigits = 9;
668     // Temporary buffer for the digits. Makes easier
669     // to reconstruct the input characters when needed.
670     char digits[10];
671
672     do {
673         octalValue = octalValue * 8 + (m_current - '0');
674         digits[maximumDigits] = m_current;
675         shift();
676         --maximumDigits;
677     } while (isASCIIOctalDigit(m_current) && maximumDigits >= 0);
678
679     if (!isASCIIDigit(m_current) && maximumDigits >= 0) {
680         returnValue = octalValue;
681         return true;
682     }
683
684     for (int i = 9; i > maximumDigits; --i)
685          record8(digits[i]);
686
687     while (isASCIIOctalDigit(m_current)) {
688         record8(m_current);
689         shift();
690     }
691
692     if (isASCIIDigit(m_current))
693         return false;
694
695     returnValue = parseIntOverflow(m_buffer8.data(), m_buffer8.size(), 8);
696     return true;
697 }
698
699 ALWAYS_INLINE bool Lexer::parseDecimal(double& returnValue)
700 {
701     // Optimization: most decimal values fit into 4 bytes.
702     uint32_t decimalValue = 0;
703
704     // Since parseOctal may be executed before parseDecimal,
705     // the m_buffer8 may hold ascii digits.
706     if (!m_buffer8.size()) {
707         int maximumDigits = 9;
708         // Temporary buffer for the digits. Makes easier
709         // to reconstruct the input characters when needed.
710         char digits[10];
711
712         do {
713             decimalValue = decimalValue * 10 + (m_current - '0');
714             digits[maximumDigits] = m_current;
715             shift();
716             --maximumDigits;
717         } while (isASCIIDigit(m_current) && maximumDigits >= 0);
718
719         if (maximumDigits >= 0 && m_current != '.' && (m_current | 0x20) != 'e') {
720             returnValue = decimalValue;
721             return true;
722         }
723
724         for (int i = 9; i > maximumDigits; --i)
725             record8(digits[i]);
726     }
727
728     while (isASCIIDigit(m_current)) {
729         record8(m_current);
730         shift();
731     }
732
733     return false;
734 }
735
736 ALWAYS_INLINE void Lexer::parseNumberAfterDecimalPoint()
737 {
738     record8('.');
739     while (isASCIIDigit(m_current)) {
740         record8(m_current);
741         shift();
742     }
743 }
744
745 ALWAYS_INLINE bool Lexer::parseNumberAfterExponentIndicator()
746 {
747     record8('e');
748     shift();
749     if (m_current == '+' || m_current == '-') {
750         record8(m_current);
751         shift();
752     }
753
754     if (!isASCIIDigit(m_current))
755         return false;
756
757     do {
758         record8(m_current);
759         shift();
760     } while (isASCIIDigit(m_current));
761     return true;
762 }
763
764 ALWAYS_INLINE bool Lexer::parseMultilineComment()
765 {
766     while (true) {
767         while (UNLIKELY(m_current == '*')) {
768             shift();
769             if (m_current == '/') {
770                 shift();
771                 return true;
772             }
773         }
774
775         if (UNLIKELY(m_current == -1))
776             return false;
777
778         if (isLineTerminator(m_current)) {
779             shiftLineTerminator();
780             m_terminator = true;
781         } else
782             shift();
783     }
784 }
785
786 bool Lexer::nextTokenIsColon()
787 {
788     const UChar* code = m_code;
789     while (code < m_codeEnd && (isWhiteSpace(*code) || isLineTerminator(*code)))
790         code++;
791         
792     return code < m_codeEnd && *code == ':';
793 }
794
795 JSTokenType Lexer::lex(JSTokenData* tokenData, JSTokenInfo* tokenInfo, unsigned lexType, bool strictMode)
796 {
797     ASSERT(!m_error);
798     ASSERT(m_buffer8.isEmpty());
799     ASSERT(m_buffer16.isEmpty());
800
801     JSTokenType token = ERRORTOK;
802     m_terminator = false;
803
804 start:
805     while (isWhiteSpace(m_current))
806         shift();
807
808     int startOffset = currentOffset();
809
810     if (UNLIKELY(m_current == -1))
811         return EOFTOK;
812
813     m_delimited = false;
814
815     CharacterType type;
816     if (LIKELY(isASCII(m_current)))
817         type = static_cast<CharacterType>(typesOfASCIICharacters[m_current]);
818     else if (isNonASCIIIdentStart(m_current))
819         type = CharacterIdentifierStart;
820     else if (isLineTerminator(m_current))
821         type = CharacterLineTerminator;
822     else
823         type = CharacterInvalid;
824
825     switch (type) {
826     case CharacterGreater:
827         shift();
828         if (m_current == '>') {
829             shift();
830             if (m_current == '>') {
831                 shift();
832                 if (m_current == '=') {
833                     shift();
834                     token = URSHIFTEQUAL;
835                     break;
836                 }
837                 token = URSHIFT;
838                 break;
839             }
840             if (m_current == '=') {
841                 shift();
842                 token = RSHIFTEQUAL;
843                 break;
844             }
845             token = RSHIFT;
846             break;
847         }
848         if (m_current == '=') {
849             shift();
850             token = GE;
851             break;
852         }
853         token = GT;
854         break;
855     case CharacterEqual:
856         shift();
857         if (m_current == '=') {
858             shift();
859             if (m_current == '=') {
860                 shift();
861                 token = STREQ;
862                 break;
863             }
864             token = EQEQ;
865             break;
866         }
867         token = EQUAL;
868         break;
869     case CharacterLess:
870         shift();
871         if (m_current == '!' && peek(1) == '-' && peek(2) == '-') {
872             // <!-- marks the beginning of a line comment (for www usage)
873             goto inSingleLineComment;
874         }
875         if (m_current == '<') {
876             shift();
877             if (m_current == '=') {
878                 shift();
879                 token = LSHIFTEQUAL;
880                 break;
881             }
882             token = LSHIFT;
883             break;
884         }
885         if (m_current == '=') {
886             shift();
887             token = LE;
888             break;
889         }
890         token = LT;
891         break;
892     case CharacterExclamationMark:
893         shift();
894         if (m_current == '=') {
895             shift();
896             if (m_current == '=') {
897                 shift();
898                 token = STRNEQ;
899                 break;
900             }
901             token = NE;
902             break;
903         }
904         token = EXCLAMATION;
905         break;
906     case CharacterAdd:
907         shift();
908         if (m_current == '+') {
909             shift();
910             token = (!m_terminator) ? PLUSPLUS : AUTOPLUSPLUS;
911             break;
912         }
913         if (m_current == '=') {
914             shift();
915             token = PLUSEQUAL;
916             break;
917         }
918         token = PLUS;
919         break;
920     case CharacterSub:
921         shift();
922         if (m_current == '-') {
923             shift();
924             if (m_atLineStart && m_current == '>') {
925                 shift();
926                 goto inSingleLineComment;
927             }
928             token = (!m_terminator) ? MINUSMINUS : AUTOMINUSMINUS;
929             break;
930         }
931         if (m_current == '=') {
932             shift();
933             token = MINUSEQUAL;
934             break;
935         }
936         token = MINUS;
937         break;
938     case CharacterMultiply:
939         shift();
940         if (m_current == '=') {
941             shift();
942             token = MULTEQUAL;
943             break;
944         }
945         token = TIMES;
946         break;
947     case CharacterSlash:
948         shift();
949         if (m_current == '/') {
950             shift();
951             goto inSingleLineComment;
952         }
953         if (m_current == '*') {
954             shift();
955             if (parseMultilineComment())
956                 goto start;
957             m_lexErrorMessage = "Multiline comment was not closed properly";
958             goto returnError;
959         }
960         if (m_current == '=') {
961             shift();
962             token = DIVEQUAL;
963             break;
964         }
965         token = DIVIDE;
966         break;
967     case CharacterAnd:
968         shift();
969         if (m_current == '&') {
970             shift();
971             token = AND;
972             break;
973         }
974         if (m_current == '=') {
975             shift();
976             token = ANDEQUAL;
977             break;
978         }
979         token = BITAND;
980         break;
981     case CharacterXor:
982         shift();
983         if (m_current == '=') {
984             shift();
985             token = XOREQUAL;
986             break;
987         }
988         token = BITXOR;
989         break;
990     case CharacterModulo:
991         shift();
992         if (m_current == '=') {
993             shift();
994             token = MODEQUAL;
995             break;
996         }
997         token = MOD;
998         break;
999     case CharacterOr:
1000         shift();
1001         if (m_current == '=') {
1002             shift();
1003             token = OREQUAL;
1004             break;
1005         }
1006         if (m_current == '|') {
1007             shift();
1008             token = OR;
1009             break;
1010         }
1011         token = BITOR;
1012         break;
1013     case CharacterOpenParen:
1014         token = OPENPAREN;
1015         shift();
1016         break;
1017     case CharacterCloseParen:
1018         token = CLOSEPAREN;
1019         shift();
1020         break;
1021     case CharacterOpenBracket:
1022         token = OPENBRACKET;
1023         shift();
1024         break;
1025     case CharacterCloseBracket:
1026         token = CLOSEBRACKET;
1027         shift();
1028         break;
1029     case CharacterComma:
1030         token = COMMA;
1031         shift();
1032         break;
1033     case CharacterColon:
1034         token = COLON;
1035         shift();
1036         break;
1037     case CharacterQuestion:
1038         token = QUESTION;
1039         shift();
1040         break;
1041     case CharacterTilde:
1042         token = TILDE;
1043         shift();
1044         break;
1045     case CharacterSemicolon:
1046         m_delimited = true;
1047         shift();
1048         token = SEMICOLON;
1049         break;
1050     case CharacterOpenBrace:
1051         tokenData->intValue = currentOffset();
1052         shift();
1053         token = OPENBRACE;
1054         break;
1055     case CharacterCloseBrace:
1056         tokenData->intValue = currentOffset();
1057         m_delimited = true;
1058         shift();
1059         token = CLOSEBRACE;
1060         break;
1061     case CharacterDot:
1062         shift();
1063         if (!isASCIIDigit(m_current)) {
1064             token = DOT;
1065             break;
1066         }
1067         goto inNumberAfterDecimalPoint;
1068     case CharacterZero:
1069         shift();
1070         if ((m_current | 0x20) == 'x' && isASCIIHexDigit(peek(1))) {
1071             parseHex(tokenData->doubleValue);
1072             token = NUMBER;
1073         } else {
1074             record8('0');
1075             if (isASCIIOctalDigit(m_current)) {
1076                 if (parseOctal(tokenData->doubleValue)) {
1077                     if (strictMode) {
1078                         m_lexErrorMessage = "Octal escapes are forbidden in strict mode";
1079                         goto returnError;
1080                     }
1081                     token = NUMBER;
1082                 }
1083             }
1084         }
1085         // Fall through into CharacterNumber
1086     case CharacterNumber:
1087         if (LIKELY(token != NUMBER)) {
1088             if (!parseDecimal(tokenData->doubleValue)) {
1089                 if (m_current == '.') {
1090                     shift();
1091 inNumberAfterDecimalPoint:
1092                     parseNumberAfterDecimalPoint();
1093                 }
1094                 if ((m_current | 0x20) == 'e')
1095                     if (!parseNumberAfterExponentIndicator()) {
1096                         m_lexErrorMessage = "Non-number found after exponent indicator";
1097                         goto returnError;
1098                     }
1099                 // Null-terminate string for strtod.
1100                 m_buffer8.append('\0');
1101                 tokenData->doubleValue = WTF::strtod(m_buffer8.data(), 0);
1102             }
1103             token = NUMBER;
1104         }
1105
1106         // No identifiers allowed directly after numeric literal, e.g. "3in" is bad.
1107         if (UNLIKELY(isIdentStart(m_current))) {
1108             m_lexErrorMessage = "At least one digit must occur after a decimal point";
1109             goto returnError;
1110         }
1111         m_buffer8.resize(0);
1112         m_delimited = false;
1113         break;
1114     case CharacterQuote:
1115         if (lexType & DontBuildStrings) {
1116             if (UNLIKELY(!parseString<false>(tokenData, strictMode)))
1117                 goto returnError;
1118         } else {
1119             if (UNLIKELY(!parseString<true>(tokenData, strictMode)))
1120                 goto returnError;
1121         }
1122         shift();
1123         m_delimited = false;
1124         token = STRING;
1125         break;
1126     case CharacterIdentifierStart:
1127         ASSERT(isIdentStart(m_current));
1128         // Fall through into CharacterBackSlash.
1129     case CharacterBackSlash:
1130         if (lexType & DontBuildKeywords)
1131             token = parseIdentifier<false>(tokenData, lexType, strictMode);
1132         else
1133             token = parseIdentifier<true>(tokenData, lexType, strictMode);
1134         break;
1135     case CharacterLineTerminator:
1136         ASSERT(isLineTerminator(m_current));
1137         shiftLineTerminator();
1138         m_atLineStart = true;
1139         m_terminator = true;
1140         goto start;
1141     case CharacterInvalid:
1142         m_lexErrorMessage = getInvalidCharMessage();
1143         goto returnError;
1144     default:
1145         ASSERT_NOT_REACHED();
1146         m_lexErrorMessage = "Internal Error";
1147         goto returnError;
1148     }
1149
1150     m_atLineStart = false;
1151     goto returnToken;
1152
1153 inSingleLineComment:
1154     while (!isLineTerminator(m_current)) {
1155         if (UNLIKELY(m_current == -1))
1156             return EOFTOK;
1157         shift();
1158     }
1159     shiftLineTerminator();
1160     m_atLineStart = true;
1161     m_terminator = true;
1162     if (!lastTokenWasRestrKeyword())
1163         goto start;
1164
1165     token = SEMICOLON;
1166     m_delimited = true;
1167     // Fall through into returnToken.
1168
1169 returnToken:
1170     tokenInfo->line = m_lineNumber;
1171     tokenInfo->startOffset = startOffset;
1172     tokenInfo->endOffset = currentOffset();
1173     m_lastToken = token;
1174     return token;
1175
1176 returnError:
1177     m_error = true;
1178     tokenInfo->line = m_lineNumber;
1179     tokenInfo->startOffset = startOffset;
1180     tokenInfo->endOffset = currentOffset();
1181     return ERRORTOK;
1182 }
1183
1184 bool Lexer::scanRegExp(const Identifier*& pattern, const Identifier*& flags, UChar patternPrefix)
1185 {
1186     ASSERT(m_buffer16.isEmpty());
1187
1188     bool lastWasEscape = false;
1189     bool inBrackets = false;
1190
1191     if (patternPrefix) {
1192         ASSERT(!isLineTerminator(patternPrefix));
1193         ASSERT(patternPrefix != '/');
1194         ASSERT(patternPrefix != '[');
1195         record16(patternPrefix);
1196     }
1197
1198     while (true) {
1199         int current = m_current;
1200
1201         if (isLineTerminator(current) || current == -1) {
1202             m_buffer16.resize(0);
1203             return false;
1204         }
1205
1206         shift();
1207
1208         if (current == '/' && !lastWasEscape && !inBrackets)
1209             break;
1210
1211         record16(current);
1212
1213         if (lastWasEscape) {
1214             lastWasEscape = false;
1215             continue;
1216         }
1217
1218         switch (current) {
1219         case '[':
1220             inBrackets = true;
1221             break;
1222         case ']':
1223             inBrackets = false;
1224             break;
1225         case '\\':
1226             lastWasEscape = true;
1227             break;
1228         }
1229     }
1230
1231     pattern = makeIdentifier(m_buffer16.data(), m_buffer16.size());
1232     m_buffer16.resize(0);
1233
1234     while (isIdentPart(m_current)) {
1235         record16(m_current);
1236         shift();
1237     }
1238
1239     flags = makeIdentifier(m_buffer16.data(), m_buffer16.size());
1240     m_buffer16.resize(0);
1241
1242     return true;
1243 }
1244
1245 bool Lexer::skipRegExp()
1246 {
1247     bool lastWasEscape = false;
1248     bool inBrackets = false;
1249
1250     while (true) {
1251         int current = m_current;
1252
1253         if (isLineTerminator(current) || current == -1)
1254             return false;
1255
1256         shift();
1257
1258         if (current == '/' && !lastWasEscape && !inBrackets)
1259             break;
1260
1261         if (lastWasEscape) {
1262             lastWasEscape = false;
1263             continue;
1264         }
1265
1266         switch (current) {
1267         case '[':
1268             inBrackets = true;
1269             break;
1270         case ']':
1271             inBrackets = false;
1272             break;
1273         case '\\':
1274             lastWasEscape = true;
1275             break;
1276         }
1277     }
1278
1279     while (isIdentPart(m_current))
1280         shift();
1281
1282     return true;
1283 }
1284
1285 void Lexer::clear()
1286 {
1287     m_arena = 0;
1288
1289     Vector<char> newBuffer8;
1290     m_buffer8.swap(newBuffer8);
1291
1292     Vector<UChar> newBuffer16;
1293     m_buffer16.swap(newBuffer16);
1294
1295     m_isReparsing = false;
1296 }
1297
1298 SourceCode Lexer::sourceCode(int openBrace, int closeBrace, int firstLine)
1299 {
1300     ASSERT(m_source->provider()->data()[openBrace] == '{');
1301     ASSERT(m_source->provider()->data()[closeBrace] == '}');
1302     return SourceCode(m_source->provider(), openBrace, closeBrace + 1, firstLine);
1303 }
1304
1305 } // namespace JSC