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