~ubuntu-branches/ubuntu/karmic/webkit/karmic-proposed

« back to all changes in this revision

Viewing changes to JavaScriptCore/parser/Lexer.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Gustavo Noronha Silva
  • Date: 2009-05-15 18:30:58 UTC
  • mto: (4.4.1 sid) (1.2.2 upstream) (16.1.1 lucid)
  • mto: This revision was merged to the branch mainline in revision 8.
  • Revision ID: james.westby@ubuntu.com-20090515183058-35m5or0ufm5tutud
Tags: upstream-1.1.7
ImportĀ upstreamĀ versionĀ 1.1.7

Show diffs side-by-side

added added

removed removed

Lines of Context:
31
31
#include <ctype.h>
32
32
#include <limits.h>
33
33
#include <string.h>
34
 
#include <wtf/ASCIICType.h>
35
34
#include <wtf/Assertions.h>
36
35
 
37
36
using namespace WTF;
38
37
using namespace Unicode;
39
38
 
40
 
// we can't specify the namespace in yacc's C output, so do it here
 
39
// We can't specify the namespace in yacc's C output, so do it here instead.
41
40
using namespace JSC;
42
41
 
43
42
#ifndef KDE_USE_FINAL
47
46
#include "Lookup.h"
48
47
#include "Lexer.lut.h"
49
48
 
50
 
// a bridge for yacc from the C world to C++
 
49
// A bridge for yacc from the C world to the C++ world.
51
50
int jscyylex(void* lvalp, void* llocp, void* globalData)
52
51
{
53
52
    return static_cast<JSGlobalData*>(globalData)->lexer->lex(lvalp, llocp);
55
54
 
56
55
namespace JSC {
57
56
 
58
 
static bool isDecimalDigit(int);
 
57
static const UChar byteOrderMark = 0xFEFF;
59
58
 
60
59
Lexer::Lexer(JSGlobalData* globalData)
61
 
    : yylineno(1)
62
 
    , m_restrKeyword(false)
63
 
    , m_eatNextIdentifier(false)
64
 
    , m_stackToken(-1)
65
 
    , m_lastToken(-1)
66
 
    , m_position(0)
67
 
    , m_code(0)
68
 
    , m_length(0)
69
 
    , m_isReparsing(false)
70
 
    , m_atLineStart(true)
71
 
    , m_current(0)
72
 
    , m_next1(0)
73
 
    , m_next2(0)
74
 
    , m_next3(0)
75
 
    , m_currentOffset(0)
76
 
    , m_nextOffset1(0)
77
 
    , m_nextOffset2(0)
78
 
    , m_nextOffset3(0)
 
60
    : m_isReparsing(false)
79
61
    , m_globalData(globalData)
80
 
    , m_mainTable(JSC::mainTable)
 
62
    , m_keywordTable(JSC::mainTable)
81
63
{
82
64
    m_buffer8.reserveInitialCapacity(initialReadBufferCapacity);
83
65
    m_buffer16.reserveInitialCapacity(initialReadBufferCapacity);
85
67
 
86
68
Lexer::~Lexer()
87
69
{
88
 
    m_mainTable.deleteTable();
89
 
}
90
 
 
91
 
void Lexer::setCode(const SourceCode& source)
92
 
{
93
 
    yylineno = source.firstLine();
94
 
    m_restrKeyword = false;
 
70
    m_keywordTable.deleteTable();
 
71
}
 
72
 
 
73
inline const UChar* Lexer::currentCharacter() const
 
74
{
 
75
    return m_code - 4;
 
76
}
 
77
 
 
78
inline int Lexer::currentOffset() const
 
79
{
 
80
    return currentCharacter() - m_codeStart;
 
81
}
 
82
 
 
83
ALWAYS_INLINE void Lexer::shift1()
 
84
{
 
85
    m_current = m_next1;
 
86
    m_next1 = m_next2;
 
87
    m_next2 = m_next3;
 
88
    if (LIKELY(m_code < m_codeEnd))
 
89
        m_next3 = m_code[0];
 
90
    else
 
91
        m_next3 = -1;
 
92
 
 
93
    ++m_code;
 
94
}
 
95
 
 
96
ALWAYS_INLINE void Lexer::shift2()
 
97
{
 
98
    m_current = m_next2;
 
99
    m_next1 = m_next3;
 
100
    if (LIKELY(m_code + 1 < m_codeEnd)) {
 
101
        m_next2 = m_code[0];
 
102
        m_next3 = m_code[1];
 
103
    } else {
 
104
        m_next2 = m_code < m_codeEnd ? m_code[0] : -1;
 
105
        m_next3 = -1;
 
106
    }
 
107
 
 
108
    m_code += 2;
 
109
}
 
110
 
 
111
ALWAYS_INLINE void Lexer::shift3()
 
112
{
 
113
    m_current = m_next3;
 
114
    if (LIKELY(m_code + 2 < m_codeEnd)) {
 
115
        m_next1 = m_code[0];
 
116
        m_next2 = m_code[1];
 
117
        m_next3 = m_code[2];
 
118
    } else {
 
119
        m_next1 = m_code < m_codeEnd ? m_code[0] : -1;
 
120
        m_next2 = m_code + 1 < m_codeEnd ? m_code[1] : -1;
 
121
        m_next3 = -1;
 
122
    }
 
123
 
 
124
    m_code += 3;
 
125
}
 
126
 
 
127
ALWAYS_INLINE void Lexer::shift4()
 
128
{
 
129
    if (LIKELY(m_code + 3 < m_codeEnd)) {
 
130
        m_current = m_code[0];
 
131
        m_next1 = m_code[1];
 
132
        m_next2 = m_code[2];
 
133
        m_next3 = m_code[3];
 
134
    } else {
 
135
        m_current = m_code < m_codeEnd ? m_code[0] : -1;
 
136
        m_next1 = m_code + 1 < m_codeEnd ? m_code[1] : -1;
 
137
        m_next2 = m_code + 2 < m_codeEnd ? m_code[2] : -1;
 
138
        m_next3 = -1;
 
139
    }
 
140
 
 
141
    m_code += 4;
 
142
}
 
143
 
 
144
void Lexer::setCode(const SourceCode& source, ParserArena& arena)
 
145
{
 
146
    m_arena = &arena.identifierArena();
 
147
 
 
148
    m_lineNumber = source.firstLine();
95
149
    m_delimited = false;
96
 
    m_eatNextIdentifier = false;
97
 
    m_stackToken = -1;
98
150
    m_lastToken = -1;
99
151
 
100
 
    m_position = source.startOffset();
 
152
    const UChar* data = source.provider()->data();
 
153
 
101
154
    m_source = &source;
102
 
    m_code = source.provider()->data();
103
 
    m_length = source.endOffset();
104
 
    m_skipLF = false;
105
 
    m_skipCR = false;
 
155
    m_codeStart = data;
 
156
    m_code = data + source.startOffset();
 
157
    m_codeEnd = data + source.endOffset();
106
158
    m_error = false;
107
159
    m_atLineStart = true;
108
160
 
109
 
    // read first characters
110
 
    shift(4);
111
 
}
112
 
 
113
 
void Lexer::shift(unsigned p)
114
 
{
115
 
    // ECMA-262 calls for stripping Cf characters here, but we only do this for BOM,
116
 
    // see <https://bugs.webkit.org/show_bug.cgi?id=4931>.
117
 
 
118
 
    while (p--) {
119
 
        m_current = m_next1;
120
 
        m_next1 = m_next2;
121
 
        m_next2 = m_next3;
122
 
        m_currentOffset = m_nextOffset1;
123
 
        m_nextOffset1 = m_nextOffset2;
124
 
        m_nextOffset2 = m_nextOffset3;
125
 
        do {
126
 
            if (m_position >= m_length) {
127
 
                m_nextOffset3 = m_position;
128
 
                m_position++;
129
 
                m_next3 = -1;
 
161
    // ECMA-262 calls for stripping all Cf characters, but we only strip BOM characters.
 
162
    // See <https://bugs.webkit.org/show_bug.cgi?id=4931> for details.
 
163
    if (source.provider()->hasBOMs()) {
 
164
        for (const UChar* p = m_codeStart; p < m_codeEnd; ++p) {
 
165
            if (UNLIKELY(*p == byteOrderMark)) {
 
166
                copyCodeWithoutBOMs();
130
167
                break;
131
168
            }
132
 
            m_nextOffset3 = m_position;
133
 
            m_next3 = m_code[m_position++];
134
 
        } while (m_next3 == 0xFEFF);
135
 
    }
136
 
}
137
 
 
138
 
// called on each new line
139
 
void Lexer::nextLine()
140
 
{
141
 
    yylineno++;
142
 
    m_atLineStart = true;
143
 
}
144
 
 
145
 
void Lexer::setDone(State s)
146
 
{
147
 
    m_state = s;
148
 
    m_done = true;
 
169
        }
 
170
    }
 
171
 
 
172
    // Read the first characters into the 4-character buffer.
 
173
    shift4();
 
174
    ASSERT(currentOffset() == source.startOffset());
 
175
}
 
176
 
 
177
void Lexer::copyCodeWithoutBOMs()
 
178
{
 
179
    // Note: In this case, the character offset data for debugging will be incorrect.
 
180
    // If it's important to correctly debug code with extraneous BOMs, then the caller
 
181
    // should strip the BOMs when creating the SourceProvider object and do its own
 
182
    // mapping of offsets within the stripped text to original text offset.
 
183
 
 
184
    m_codeWithoutBOMs.reserveCapacity(m_codeEnd - m_code);
 
185
    for (const UChar* p = m_code; p < m_codeEnd; ++p) {
 
186
        UChar c = *p;
 
187
        if (c != byteOrderMark)
 
188
            m_codeWithoutBOMs.append(c);
 
189
    }
 
190
    ptrdiff_t startDelta = m_codeStart - m_code;
 
191
    m_code = m_codeWithoutBOMs.data();
 
192
    m_codeStart = m_code + startDelta;
 
193
    m_codeEnd = m_codeWithoutBOMs.data() + m_codeWithoutBOMs.size();
 
194
}
 
195
 
 
196
void Lexer::shiftLineTerminator()
 
197
{
 
198
    ASSERT(isLineTerminator(m_current));
 
199
 
 
200
    // Allow both CRLF and LFCR.
 
201
    if (m_current + m_next1 == '\n' + '\r')
 
202
        shift2();
 
203
    else
 
204
        shift1();
 
205
 
 
206
    ++m_lineNumber;
 
207
}
 
208
 
 
209
ALWAYS_INLINE const Identifier* Lexer::makeIdentifier(const UChar* characters, size_t length)
 
210
{
 
211
    return &JSC::makeIdentifier(*m_arena, m_globalData, characters, length);
 
212
}
 
213
 
 
214
inline bool Lexer::lastTokenWasRestrKeyword() const
 
215
{
 
216
    return m_lastToken == CONTINUE || m_lastToken == BREAK || m_lastToken == RETURN || m_lastToken == THROW;
 
217
}
 
218
 
 
219
static NEVER_INLINE bool isNonASCIIIdentStart(int c)
 
220
{
 
221
    return category(c) & (Letter_Uppercase | Letter_Lowercase | Letter_Titlecase | Letter_Modifier | Letter_Other);
 
222
}
 
223
 
 
224
static inline bool isIdentStart(int c)
 
225
{
 
226
    return isASCII(c) ? isASCIIAlpha(c) || c == '$' || c == '_' : isNonASCIIIdentStart(c);
 
227
}
 
228
 
 
229
static NEVER_INLINE bool isNonASCIIIdentPart(int c)
 
230
{
 
231
    return category(c) & (Letter_Uppercase | Letter_Lowercase | Letter_Titlecase | Letter_Modifier | Letter_Other
 
232
        | Mark_NonSpacing | Mark_SpacingCombining | Number_DecimalDigit | Punctuation_Connector);
 
233
}
 
234
 
 
235
static inline bool isIdentPart(int c)
 
236
{
 
237
    return isASCII(c) ? isASCIIAlphanumeric(c) || c == '$' || c == '_' : isNonASCIIIdentPart(c);
 
238
}
 
239
 
 
240
static inline int singleEscape(int c)
 
241
{
 
242
    switch (c) {
 
243
        case 'b':
 
244
            return 0x08;
 
245
        case 't':
 
246
            return 0x09;
 
247
        case 'n':
 
248
            return 0x0A;
 
249
        case 'v':
 
250
            return 0x0B;
 
251
        case 'f':
 
252
            return 0x0C;
 
253
        case 'r':
 
254
            return 0x0D;
 
255
        default:
 
256
            return c;
 
257
    }
 
258
}
 
259
 
 
260
inline void Lexer::record8(int c)
 
261
{
 
262
    ASSERT(c >= 0);
 
263
    ASSERT(c <= 0xFF);
 
264
    m_buffer8.append(static_cast<char>(c));
 
265
}
 
266
 
 
267
inline void Lexer::record16(UChar c)
 
268
{
 
269
    m_buffer16.append(c);
 
270
}
 
271
 
 
272
inline void Lexer::record16(int c)
 
273
{
 
274
    ASSERT(c >= 0);
 
275
    ASSERT(c <= USHRT_MAX);
 
276
    record16(UChar(static_cast<unsigned short>(c)));
149
277
}
150
278
 
151
279
int Lexer::lex(void* p1, void* p2)
152
280
{
 
281
    ASSERT(!m_error);
 
282
    ASSERT(m_buffer8.isEmpty());
 
283
    ASSERT(m_buffer16.isEmpty());
 
284
 
153
285
    YYSTYPE* lvalp = static_cast<YYSTYPE*>(p1);
154
286
    YYLTYPE* llocp = static_cast<YYLTYPE*>(p2);
155
287
    int token = 0;
156
 
    m_state = Start;
157
 
    unsigned short stringType = 0; // either single or double quotes
158
 
    m_buffer8.clear();
159
 
    m_buffer16.clear();
160
 
    m_done = false;
161
288
    m_terminator = false;
162
 
    m_skipLF = false;
163
 
    m_skipCR = false;
164
 
 
165
 
    // did we push a token on the stack previously ?
166
 
    // (after an automatic semicolon insertion)
167
 
    if (m_stackToken >= 0) {
168
 
        setDone(Other);
169
 
        token = m_stackToken;
170
 
        m_stackToken = 0;
171
 
    }
172
 
    int startOffset = m_currentOffset;
173
 
    while (!m_done) {
174
 
        if (m_skipLF && m_current != '\n') // found \r but not \n afterwards
175
 
            m_skipLF = false;
176
 
        if (m_skipCR && m_current != '\r') // found \n but not \r afterwards
177
 
            m_skipCR = false;
178
 
        if (m_skipLF || m_skipCR) { // found \r\n or \n\r -> eat the second one
179
 
            m_skipLF = false;
180
 
            m_skipCR = false;
181
 
            shift(1);
182
 
        }
183
 
        switch (m_state) {
184
 
            case Start:
185
 
                startOffset = m_currentOffset;
186
 
                if (isWhiteSpace()) {
187
 
                    // do nothing
188
 
                } else if (m_current == '/' && m_next1 == '/') {
189
 
                    shift(1);
190
 
                    m_state = InSingleLineComment;
191
 
                } else if (m_current == '/' && m_next1 == '*') {
192
 
                    shift(1);
193
 
                    m_state = InMultiLineComment;
194
 
                } else if (m_current == -1) {
195
 
                    if (!m_terminator && !m_delimited && !m_isReparsing) {
196
 
                        // automatic semicolon insertion if program incomplete
197
 
                        token = ';';
198
 
                        m_stackToken = 0;
199
 
                        setDone(Other);
200
 
                    } else
201
 
                        setDone(Eof);
202
 
                } else if (isLineTerminator()) {
203
 
                    nextLine();
204
 
                    m_terminator = true;
205
 
                    if (m_restrKeyword) {
206
 
                        token = ';';
207
 
                        setDone(Other);
208
 
                    }
209
 
                } else if (m_current == '"' || m_current == '\'') {
210
 
                    m_state = InString;
211
 
                    stringType = static_cast<unsigned short>(m_current);
212
 
                } else if (isIdentStart(m_current)) {
213
 
                    record16(m_current);
214
 
                    m_state = InIdentifierOrKeyword;
215
 
                } else if (m_current == '\\')
216
 
                    m_state = InIdentifierStartUnicodeEscapeStart;
217
 
                else if (m_current == '0') {
218
 
                    record8(m_current);
219
 
                    m_state = InNum0;
220
 
                } else if (isDecimalDigit(m_current)) {
221
 
                    record8(m_current);
222
 
                    m_state = InNum;
223
 
                } else if (m_current == '.' && isDecimalDigit(m_next1)) {
224
 
                    record8(m_current);
225
 
                    m_state = InDecimal;
226
 
                    // <!-- marks the beginning of a line comment (for www usage)
227
 
                } else if (m_current == '<' && m_next1 == '!' && m_next2 == '-' && m_next3 == '-') {
228
 
                    shift(3);
229
 
                    m_state = InSingleLineComment;
230
 
                    // same for -->
231
 
                } else if (m_atLineStart && m_current == '-' && m_next1 == '-' &&  m_next2 == '>') {
232
 
                    shift(2);
233
 
                    m_state = InSingleLineComment;
234
 
                } else {
235
 
                    token = matchPunctuator(lvalp->intValue, m_current, m_next1, m_next2, m_next3);
236
 
                    if (token != -1)
237
 
                        setDone(Other);
238
 
                    else
239
 
                        setDone(Bad);
240
 
                }
241
 
                break;
242
 
            case InString:
243
 
                if (m_current == stringType) {
244
 
                    shift(1);
245
 
                    setDone(String);
246
 
                } else if (isLineTerminator() || m_current == -1)
247
 
                    setDone(Bad);
248
 
                else if (m_current == '\\')
249
 
                    m_state = InEscapeSequence;
250
 
                else
251
 
                    record16(m_current);
252
 
                break;
253
 
            // Escape Sequences inside of strings
254
 
            case InEscapeSequence:
255
 
                if (isOctalDigit(m_current)) {
256
 
                    if (m_current >= '0' && m_current <= '3' &&
257
 
                        isOctalDigit(m_next1) && isOctalDigit(m_next2)) {
258
 
                        record16(convertOctal(m_current, m_next1, m_next2));
259
 
                        shift(2);
260
 
                        m_state = InString;
261
 
                    } else if (isOctalDigit(m_current) && isOctalDigit(m_next1)) {
262
 
                        record16(convertOctal('0', m_current, m_next1));
263
 
                        shift(1);
264
 
                        m_state = InString;
265
 
                    } else if (isOctalDigit(m_current)) {
266
 
                        record16(convertOctal('0', '0', m_current));
267
 
                        m_state = InString;
268
 
                    } else
269
 
                        setDone(Bad);
270
 
                } else if (m_current == 'x')
271
 
                    m_state = InHexEscape;
272
 
                else if (m_current == 'u')
273
 
                    m_state = InUnicodeEscape;
274
 
                else if (isLineTerminator()) {
275
 
                    nextLine();
276
 
                    m_state = InString;
277
 
                } else {
278
 
                    record16(singleEscape(static_cast<unsigned short>(m_current)));
279
 
                    m_state = InString;
280
 
                }
281
 
                break;
282
 
            case InHexEscape:
283
 
                if (isHexDigit(m_current) && isHexDigit(m_next1)) {
284
 
                    m_state = InString;
285
 
                    record16(convertHex(m_current, m_next1));
286
 
                    shift(1);
287
 
                } else if (m_current == stringType) {
288
 
                    record16('x');
289
 
                    shift(1);
290
 
                    setDone(String);
291
 
                } else {
292
 
                    record16('x');
293
 
                    record16(m_current);
294
 
                    m_state = InString;
295
 
                }
296
 
                break;
297
 
            case InUnicodeEscape:
298
 
                if (isHexDigit(m_current) && isHexDigit(m_next1) && isHexDigit(m_next2) && isHexDigit(m_next3)) {
299
 
                    record16(convertUnicode(m_current, m_next1, m_next2, m_next3));
300
 
                    shift(3);
301
 
                    m_state = InString;
302
 
                } else if (m_current == stringType) {
303
 
                    record16('u');
304
 
                    shift(1);
305
 
                    setDone(String);
306
 
                } else
307
 
                    setDone(Bad);
308
 
                break;
309
 
            case InSingleLineComment:
310
 
                if (isLineTerminator()) {
311
 
                    nextLine();
312
 
                    m_terminator = true;
313
 
                    if (m_restrKeyword) {
314
 
                        token = ';';
315
 
                        setDone(Other);
316
 
                    } else
317
 
                        m_state = Start;
318
 
                } else if (m_current == -1)
319
 
                    setDone(Eof);
320
 
                break;
321
 
            case InMultiLineComment:
322
 
                if (m_current == -1)
323
 
                    setDone(Bad);
324
 
                else if (isLineTerminator())
325
 
                    nextLine();
326
 
                else if (m_current == '*' && m_next1 == '/') {
327
 
                    m_state = Start;
328
 
                    shift(1);
329
 
                }
330
 
                break;
331
 
            case InIdentifierOrKeyword:
332
 
            case InIdentifier:
333
 
                if (isIdentPart(m_current))
334
 
                    record16(m_current);
335
 
                else if (m_current == '\\')
336
 
                    m_state = InIdentifierPartUnicodeEscapeStart;
337
 
                else
338
 
                    setDone(m_state == InIdentifierOrKeyword ? IdentifierOrKeyword : Identifier);
339
 
                break;
340
 
            case InNum0:
341
 
                if (m_current == 'x' || m_current == 'X') {
342
 
                    record8(m_current);
343
 
                    m_state = InHex;
344
 
                } else if (m_current == '.') {
345
 
                    record8(m_current);
346
 
                    m_state = InDecimal;
347
 
                } else if (m_current == 'e' || m_current == 'E') {
348
 
                    record8(m_current);
349
 
                    m_state = InExponentIndicator;
350
 
                } else if (isOctalDigit(m_current)) {
351
 
                    record8(m_current);
352
 
                    m_state = InOctal;
353
 
                } else if (isDecimalDigit(m_current)) {
354
 
                    record8(m_current);
355
 
                    m_state = InDecimal;
356
 
                } else
357
 
                    setDone(Number);
358
 
                break;
359
 
            case InHex:
360
 
                if (isHexDigit(m_current))
361
 
                    record8(m_current);
362
 
                else
363
 
                    setDone(Hex);
364
 
                break;
365
 
            case InOctal:
366
 
                if (isOctalDigit(m_current))
367
 
                    record8(m_current);
368
 
                else if (isDecimalDigit(m_current)) {
369
 
                    record8(m_current);
370
 
                    m_state = InDecimal;
371
 
                } else
372
 
                    setDone(Octal);
373
 
                break;
374
 
            case InNum:
375
 
                if (isDecimalDigit(m_current))
376
 
                    record8(m_current);
377
 
                else if (m_current == '.') {
378
 
                    record8(m_current);
379
 
                    m_state = InDecimal;
380
 
                } else if (m_current == 'e' || m_current == 'E') {
381
 
                    record8(m_current);
382
 
                    m_state = InExponentIndicator;
383
 
                } else
384
 
                    setDone(Number);
385
 
                break;
386
 
            case InDecimal:
387
 
                if (isDecimalDigit(m_current))
388
 
                    record8(m_current);
389
 
                else if (m_current == 'e' || m_current == 'E') {
390
 
                    record8(m_current);
391
 
                    m_state = InExponentIndicator;
392
 
                } else
393
 
                    setDone(Number);
394
 
                break;
395
 
            case InExponentIndicator:
396
 
                if (m_current == '+' || m_current == '-')
397
 
                    record8(m_current);
398
 
                else if (isDecimalDigit(m_current)) {
399
 
                    record8(m_current);
400
 
                    m_state = InExponent;
401
 
                } else
402
 
                    setDone(Bad);
403
 
                break;
404
 
            case InExponent:
405
 
                if (isDecimalDigit(m_current))
406
 
                    record8(m_current);
407
 
                else
408
 
                    setDone(Number);
409
 
                break;
410
 
            case InIdentifierStartUnicodeEscapeStart:
411
 
                if (m_current == 'u')
412
 
                    m_state = InIdentifierStartUnicodeEscape;
413
 
                else
414
 
                    setDone(Bad);
415
 
                break;
416
 
            case InIdentifierPartUnicodeEscapeStart:
417
 
                if (m_current == 'u')
418
 
                    m_state = InIdentifierPartUnicodeEscape;
419
 
                else
420
 
                    setDone(Bad);
421
 
                break;
422
 
            case InIdentifierStartUnicodeEscape:
423
 
                if (!isHexDigit(m_current) || !isHexDigit(m_next1) || !isHexDigit(m_next2) || !isHexDigit(m_next3)) {
424
 
                    setDone(Bad);
425
 
                    break;
426
 
                }
427
 
                token = convertUnicode(m_current, m_next1, m_next2, m_next3);
428
 
                shift(3);
429
 
                if (!isIdentStart(token)) {
430
 
                    setDone(Bad);
431
 
                    break;
432
 
                }
433
 
                record16(token);
434
 
                m_state = InIdentifier;
435
 
                break;
436
 
            case InIdentifierPartUnicodeEscape:
437
 
                if (!isHexDigit(m_current) || !isHexDigit(m_next1) || !isHexDigit(m_next2) || !isHexDigit(m_next3)) {
438
 
                    setDone(Bad);
439
 
                    break;
440
 
                }
441
 
                token = convertUnicode(m_current, m_next1, m_next2, m_next3);
442
 
                shift(3);
443
 
                if (!isIdentPart(token)) {
444
 
                    setDone(Bad);
445
 
                    break;
446
 
                }
447
 
                record16(token);
448
 
                m_state = InIdentifier;
449
 
                break;
450
 
            default:
451
 
                ASSERT(!"Unhandled state in switch statement");
452
 
        }
453
 
 
454
 
        // move on to the next character
455
 
        if (!m_done)
456
 
            shift(1);
457
 
        if (m_state != Start && m_state != InSingleLineComment)
458
 
            m_atLineStart = false;
459
 
    }
460
 
 
461
 
    // no identifiers allowed directly after numeric literal, e.g. "3in" is bad
462
 
    if ((m_state == Number || m_state == Octal || m_state == Hex) && isIdentStart(m_current))
463
 
        m_state = Bad;
464
 
 
465
 
    // terminate string
466
 
    m_buffer8.append('\0');
467
 
 
468
 
#ifdef JSC_DEBUG_LEX
469
 
    fprintf(stderr, "line: %d ", lineNo());
470
 
    fprintf(stderr, "yytext (%x): ", m_buffer8[0]);
471
 
    fprintf(stderr, "%s ", m_buffer8.data());
472
 
#endif
473
 
 
474
 
    double dval = 0;
475
 
    if (m_state == Number)
476
 
        dval = WTF::strtod(m_buffer8.data(), 0L);
477
 
    else if (m_state == Hex) { // scan hex numbers
478
 
        const char* p = m_buffer8.data() + 2;
479
 
        while (char c = *p++) {
480
 
            dval *= 16;
481
 
            dval += convertHex(c);
482
 
        }
483
 
 
484
 
        if (dval >= mantissaOverflowLowerBound)
485
 
            dval = parseIntOverflow(m_buffer8.data() + 2, p - (m_buffer8.data() + 3), 16);
486
 
 
487
 
        m_state = Number;
488
 
    } else if (m_state == Octal) {   // scan octal number
489
 
        const char* p = m_buffer8.data() + 1;
490
 
        while (char c = *p++) {
491
 
            dval *= 8;
492
 
            dval += c - '0';
493
 
        }
494
 
 
495
 
        if (dval >= mantissaOverflowLowerBound)
496
 
            dval = parseIntOverflow(m_buffer8.data() + 1, p - (m_buffer8.data() + 2), 8);
497
 
 
498
 
        m_state = Number;
499
 
    }
500
 
 
501
 
#ifdef JSC_DEBUG_LEX
502
 
    switch (m_state) {
503
 
        case Eof:
504
 
            printf("(EOF)\n");
505
 
            break;
506
 
        case Other:
507
 
            printf("(Other)\n");
508
 
            break;
509
 
        case Identifier:
510
 
            printf("(Identifier)/(Keyword)\n");
511
 
            break;
512
 
        case String:
513
 
            printf("(String)\n");
514
 
            break;
515
 
        case Number:
516
 
            printf("(Number)\n");
517
 
            break;
518
 
        default:
519
 
            printf("(unknown)");
520
 
    }
521
 
#endif
522
 
 
523
 
    if (m_state != Identifier)
524
 
        m_eatNextIdentifier = false;
525
 
 
526
 
    m_restrKeyword = false;
 
289
 
 
290
start:
 
291
    while (isWhiteSpace(m_current))
 
292
        shift1();
 
293
 
 
294
    int startOffset = currentOffset();
 
295
 
 
296
    if (m_current == -1) {
 
297
        if (!m_terminator && !m_delimited && !m_isReparsing) {
 
298
            // automatic semicolon insertion if program incomplete
 
299
            token = ';';
 
300
            goto doneSemicolon;
 
301
        }
 
302
        return 0;
 
303
    }
 
304
 
527
305
    m_delimited = false;
528
 
    llocp->first_line = yylineno;
529
 
    llocp->last_line = yylineno;
530
 
    llocp->first_column = startOffset;
531
 
    llocp->last_column = m_currentOffset;
532
 
    switch (m_state) {
533
 
        case Eof:
534
 
            token = 0;
535
 
            break;
536
 
        case Other:
537
 
            if (token == '}' || token == ';')
538
 
                m_delimited = true;
539
 
            break;
540
 
        case Identifier:
541
 
            // Apply anonymous-function hack below (eat the identifier).
542
 
            if (m_eatNextIdentifier) {
543
 
                m_eatNextIdentifier = false;
544
 
                token = lex(lvalp, llocp);
545
 
                break;
546
 
            }
547
 
            lvalp->ident = makeIdentifier(m_buffer16);
548
 
            token = IDENT;
549
 
            break;
550
 
        case IdentifierOrKeyword: {
551
 
            lvalp->ident = makeIdentifier(m_buffer16);
552
 
            const HashEntry* entry = m_mainTable.entry(m_globalData, *lvalp->ident);
553
 
            if (!entry) {
554
 
                // Lookup for keyword failed, means this is an identifier.
555
 
                token = IDENT;
556
 
                break;
557
 
            }
558
 
            token = entry->lexerValue();
559
 
            // Hack for "f = function somename() { ... }"; too hard to get into the grammar.
560
 
            m_eatNextIdentifier = token == FUNCTION && m_lastToken == '=';
561
 
            if (token == CONTINUE || token == BREAK || token == RETURN || token == THROW)
562
 
                m_restrKeyword = true;
563
 
            break;
564
 
        }
565
 
        case String:
566
 
            // Atomize constant strings in case they're later used in property lookup.
567
 
            lvalp->ident = makeIdentifier(m_buffer16);
568
 
            token = STRING;
569
 
            break;
570
 
        case Number:
571
 
            lvalp->doubleValue = dval;
572
 
            token = NUMBER;
573
 
            break;
574
 
        case Bad:
575
 
#ifdef JSC_DEBUG_LEX
576
 
            fprintf(stderr, "yylex: ERROR.\n");
577
 
#endif
578
 
            m_error = true;
579
 
            return -1;
580
 
        default:
581
 
            ASSERT(!"unhandled numeration value in switch");
582
 
            m_error = true;
583
 
            return -1;
584
 
    }
585
 
    m_lastToken = token;
586
 
    return token;
587
 
}
588
 
 
589
 
bool Lexer::isWhiteSpace() const
590
 
{
591
 
    return isWhiteSpace(m_current);
592
 
}
593
 
 
594
 
bool Lexer::isLineTerminator()
595
 
{
596
 
    bool cr = (m_current == '\r');
597
 
    bool lf = (m_current == '\n');
598
 
    if (cr)
599
 
        m_skipLF = true;
600
 
    else if (lf)
601
 
        m_skipCR = true;
602
 
    return cr || lf || m_current == 0x2028 || m_current == 0x2029;
603
 
}
604
 
 
605
 
bool Lexer::isIdentStart(int c)
606
 
{
607
 
    return isASCIIAlpha(c) || c == '$' || c == '_' || (!isASCII(c) && (category(c) & (Letter_Uppercase | Letter_Lowercase | Letter_Titlecase | Letter_Modifier | Letter_Other)));
608
 
}
609
 
 
610
 
bool Lexer::isIdentPart(int c)
611
 
{
612
 
    return isASCIIAlphanumeric(c) || c == '$' || c == '_' || (!isASCII(c) && (category(c) & (Letter_Uppercase | Letter_Lowercase | Letter_Titlecase | Letter_Modifier | Letter_Other
613
 
                            | Mark_NonSpacing | Mark_SpacingCombining | Number_DecimalDigit | Punctuation_Connector)));
614
 
}
615
 
 
616
 
static bool isDecimalDigit(int c)
617
 
{
618
 
    return isASCIIDigit(c);
619
 
}
620
 
 
621
 
bool Lexer::isHexDigit(int c)
622
 
{
623
 
    return isASCIIHexDigit(c); 
624
 
}
625
 
 
626
 
bool Lexer::isOctalDigit(int c)
627
 
{
628
 
    return isASCIIOctalDigit(c);
629
 
}
630
 
 
631
 
int Lexer::matchPunctuator(int& charPos, int c1, int c2, int c3, int c4)
632
 
{
633
 
    if (c1 == '>' && c2 == '>' && c3 == '>' && c4 == '=') {
634
 
        shift(4);
635
 
        return URSHIFTEQUAL;
636
 
    }
637
 
    if (c1 == '=' && c2 == '=' && c3 == '=') {
638
 
        shift(3);
639
 
        return STREQ;
640
 
    }
641
 
    if (c1 == '!' && c2 == '=' && c3 == '=') {
642
 
        shift(3);
643
 
        return STRNEQ;
644
 
    }
645
 
    if (c1 == '>' && c2 == '>' && c3 == '>') {
646
 
        shift(3);
647
 
        return URSHIFT;
648
 
    }
649
 
    if (c1 == '<' && c2 == '<' && c3 == '=') {
650
 
        shift(3);
651
 
        return LSHIFTEQUAL;
652
 
    }
653
 
    if (c1 == '>' && c2 == '>' && c3 == '=') {
654
 
        shift(3);
655
 
        return RSHIFTEQUAL;
656
 
    }
657
 
    if (c1 == '<' && c2 == '=') {
658
 
        shift(2);
659
 
        return LE;
660
 
    }
661
 
    if (c1 == '>' && c2 == '=') {
662
 
        shift(2);
663
 
        return GE;
664
 
    }
665
 
    if (c1 == '!' && c2 == '=') {
666
 
        shift(2);
667
 
        return NE;
668
 
    }
669
 
    if (c1 == '+' && c2 == '+') {
670
 
        shift(2);
671
 
        if (m_terminator)
672
 
            return AUTOPLUSPLUS;
673
 
        return PLUSPLUS;
674
 
    }
675
 
    if (c1 == '-' && c2 == '-') {
676
 
        shift(2);
677
 
        if (m_terminator)
678
 
            return AUTOMINUSMINUS;
679
 
        return MINUSMINUS;
680
 
    }
681
 
    if (c1 == '=' && c2 == '=') {
682
 
        shift(2);
683
 
        return EQEQ;
684
 
    }
685
 
    if (c1 == '+' && c2 == '=') {
686
 
        shift(2);
687
 
        return PLUSEQUAL;
688
 
    }
689
 
    if (c1 == '-' && c2 == '=') {
690
 
        shift(2);
691
 
        return MINUSEQUAL;
692
 
    }
693
 
    if (c1 == '*' && c2 == '=') {
694
 
        shift(2);
695
 
        return MULTEQUAL;
696
 
    }
697
 
    if (c1 == '/' && c2 == '=') {
698
 
        shift(2);
699
 
        return DIVEQUAL;
700
 
    }
701
 
    if (c1 == '&' && c2 == '=') {
702
 
        shift(2);
703
 
        return ANDEQUAL;
704
 
    }
705
 
    if (c1 == '^' && c2 == '=') {
706
 
        shift(2);
707
 
        return XOREQUAL;
708
 
    }
709
 
    if (c1 == '%' && c2 == '=') {
710
 
        shift(2);
711
 
        return MODEQUAL;
712
 
    }
713
 
    if (c1 == '|' && c2 == '=') {
714
 
        shift(2);
715
 
        return OREQUAL;
716
 
    }
717
 
    if (c1 == '<' && c2 == '<') {
718
 
        shift(2);
719
 
        return LSHIFT;
720
 
    }
721
 
    if (c1 == '>' && c2 == '>') {
722
 
        shift(2);
723
 
        return RSHIFT;
724
 
    }
725
 
    if (c1 == '&' && c2 == '&') {
726
 
        shift(2);
727
 
        return AND;
728
 
    }
729
 
    if (c1 == '|' && c2 == '|') {
730
 
        shift(2);
731
 
        return OR;
732
 
    }
733
 
 
734
 
    switch (c1) {
 
306
    switch (m_current) {
 
307
        case '>':
 
308
            if (m_next1 == '>' && m_next2 == '>') {
 
309
                if (m_next3 == '=') {
 
310
                    shift4();
 
311
                    token = URSHIFTEQUAL;
 
312
                    break;
 
313
                }
 
314
                shift3();
 
315
                token = URSHIFT;
 
316
                break;
 
317
            }
 
318
            if (m_next1 == '>') {
 
319
                if (m_next2 == '=') {
 
320
                    shift3();
 
321
                    token = RSHIFTEQUAL;
 
322
                    break;
 
323
                }
 
324
                shift2();
 
325
                token = RSHIFT;
 
326
                break;
 
327
            }
 
328
            if (m_next1 == '=') {
 
329
                shift2();
 
330
                token = GE;
 
331
                break;
 
332
            }
 
333
            shift1();
 
334
            token = '>';
 
335
            break;
735
336
        case '=':
736
 
        case '>':
 
337
            if (m_next1 == '=') {
 
338
                if (m_next2 == '=') {
 
339
                    shift3();
 
340
                    token = STREQ;
 
341
                    break;
 
342
                }
 
343
                shift2();
 
344
                token = EQEQ;
 
345
                break;
 
346
            }
 
347
            shift1();
 
348
            token = '=';
 
349
            break;
 
350
        case '!':
 
351
            if (m_next1 == '=') {
 
352
                if (m_next2 == '=') {
 
353
                    shift3();
 
354
                    token = STRNEQ;
 
355
                    break;
 
356
                }
 
357
                shift2();
 
358
                token = NE;
 
359
                break;
 
360
            }
 
361
            shift1();
 
362
            token = '!';
 
363
            break;
737
364
        case '<':
738
 
        case ',':
739
 
        case '!':
740
 
        case '~':
741
 
        case '?':
742
 
        case ':':
743
 
        case '.':
 
365
            if (m_next1 == '!' && m_next2 == '-' && m_next3 == '-') {
 
366
                // <!-- marks the beginning of a line comment (for www usage)
 
367
                shift4();
 
368
                goto inSingleLineComment;
 
369
            }
 
370
            if (m_next1 == '<') {
 
371
                if (m_next2 == '=') {
 
372
                    shift3();
 
373
                    token = LSHIFTEQUAL;
 
374
                    break;
 
375
                }
 
376
                shift2();
 
377
                token = LSHIFT;
 
378
                break;
 
379
            }
 
380
            if (m_next1 == '=') {
 
381
                shift2();
 
382
                token = LE;
 
383
                break;
 
384
            }
 
385
            shift1();
 
386
            token = '<';
 
387
            break;
744
388
        case '+':
 
389
            if (m_next1 == '+') {
 
390
                shift2();
 
391
                if (m_terminator) {
 
392
                    token = AUTOPLUSPLUS;
 
393
                    break;
 
394
                }
 
395
                token = PLUSPLUS;
 
396
                break;
 
397
            }
 
398
            if (m_next1 == '=') {
 
399
                shift2();
 
400
                token = PLUSEQUAL;
 
401
                break;
 
402
            }
 
403
            shift1();
 
404
            token = '+';
 
405
            break;
745
406
        case '-':
 
407
            if (m_next1 == '-') {
 
408
                if (m_atLineStart && m_next2 == '>') {
 
409
                    shift3();
 
410
                    goto inSingleLineComment;
 
411
                }
 
412
                shift2();
 
413
                if (m_terminator) {
 
414
                    token = AUTOMINUSMINUS;
 
415
                    break;
 
416
                }
 
417
                token = MINUSMINUS;
 
418
                break;
 
419
            }
 
420
            if (m_next1 == '=') {
 
421
                shift2();
 
422
                token = MINUSEQUAL;
 
423
                break;
 
424
            }
 
425
            shift1();
 
426
            token = '-';
 
427
            break;
746
428
        case '*':
 
429
            if (m_next1 == '=') {
 
430
                shift2();
 
431
                token = MULTEQUAL;
 
432
                break;
 
433
            }
 
434
            shift1();
 
435
            token = '*';
 
436
            break;
747
437
        case '/':
 
438
            if (m_next1 == '/') {
 
439
                shift2();
 
440
                goto inSingleLineComment;
 
441
            }
 
442
            if (m_next1 == '*')
 
443
                goto inMultiLineComment;
 
444
            if (m_next1 == '=') {
 
445
                shift2();
 
446
                token = DIVEQUAL;
 
447
                break;
 
448
            }
 
449
            shift1();
 
450
            token = '/';
 
451
            break;
748
452
        case '&':
749
 
        case '|':
 
453
            if (m_next1 == '&') {
 
454
                shift2();
 
455
                token = AND;
 
456
                break;
 
457
            }
 
458
            if (m_next1 == '=') {
 
459
                shift2();
 
460
                token = ANDEQUAL;
 
461
                break;
 
462
            }
 
463
            shift1();
 
464
            token = '&';
 
465
            break;
750
466
        case '^':
 
467
            if (m_next1 == '=') {
 
468
                shift2();
 
469
                token = XOREQUAL;
 
470
                break;
 
471
            }
 
472
            shift1();
 
473
            token = '^';
 
474
            break;
751
475
        case '%':
 
476
            if (m_next1 == '=') {
 
477
                shift2();
 
478
                token = MODEQUAL;
 
479
                break;
 
480
            }
 
481
            shift1();
 
482
            token = '%';
 
483
            break;
 
484
        case '|':
 
485
            if (m_next1 == '=') {
 
486
                shift2();
 
487
                token = OREQUAL;
 
488
                break;
 
489
            }
 
490
            if (m_next1 == '|') {
 
491
                shift2();
 
492
                token = OR;
 
493
                break;
 
494
            }
 
495
            shift1();
 
496
            token = '|';
 
497
            break;
 
498
        case '.':
 
499
            if (isASCIIDigit(m_next1)) {
 
500
                record8('.');
 
501
                shift1();
 
502
                goto inNumberAfterDecimalPoint;
 
503
            }
 
504
            token = '.';
 
505
            shift1();
 
506
            break;
 
507
        case ',':
 
508
        case '~':
 
509
        case '?':
 
510
        case ':':
752
511
        case '(':
753
512
        case ')':
754
513
        case '[':
755
514
        case ']':
 
515
            token = m_current;
 
516
            shift1();
 
517
            break;
756
518
        case ';':
757
 
            shift(1);
758
 
            return static_cast<int>(c1);
 
519
            shift1();
 
520
            m_delimited = true;
 
521
            token = ';';
 
522
            break;
759
523
        case '{':
760
 
            charPos = m_currentOffset;
761
 
            shift(1);
762
 
            return OPENBRACE;
 
524
            lvalp->intValue = currentOffset();
 
525
            shift1();
 
526
            token = OPENBRACE;
 
527
            break;
763
528
        case '}':
764
 
            charPos = m_currentOffset;
765
 
            shift(1);
766
 
            return CLOSEBRACE;
767
 
        default:
768
 
            return -1;
769
 
    }
770
 
}
771
 
 
772
 
unsigned short Lexer::singleEscape(unsigned short c)
773
 
{
774
 
    switch (c) {
775
 
        case 'b':
776
 
            return 0x08;
777
 
        case 't':
778
 
            return 0x09;
779
 
        case 'n':
780
 
            return 0x0A;
781
 
        case 'v':
782
 
            return 0x0B;
783
 
        case 'f':
784
 
            return 0x0C;
785
 
        case 'r':
786
 
            return 0x0D;
 
529
            lvalp->intValue = currentOffset();
 
530
            shift1();
 
531
            m_delimited = true;
 
532
            token = CLOSEBRACE;
 
533
            break;
 
534
        case '\\':
 
535
            goto startIdentifierWithBackslash;
 
536
        case '0':
 
537
            goto startNumberWithZeroDigit;
 
538
        case '1':
 
539
        case '2':
 
540
        case '3':
 
541
        case '4':
 
542
        case '5':
 
543
        case '6':
 
544
        case '7':
 
545
        case '8':
 
546
        case '9':
 
547
            goto startNumber;
787
548
        case '"':
788
 
            return 0x22;
789
549
        case '\'':
790
 
            return 0x27;
791
 
        case '\\':
792
 
            return 0x5C;
 
550
            goto startString;
793
551
        default:
794
 
            return c;
795
 
    }
796
 
}
797
 
 
798
 
unsigned short Lexer::convertOctal(int c1, int c2, int c3)
799
 
{
800
 
    return static_cast<unsigned short>((c1 - '0') * 64 + (c2 - '0') * 8 + c3 - '0');
801
 
}
802
 
 
803
 
unsigned char Lexer::convertHex(int c)
804
 
{
805
 
    if (c >= '0' && c <= '9')
806
 
        return static_cast<unsigned char>(c - '0');
807
 
    if (c >= 'a' && c <= 'f')
808
 
        return static_cast<unsigned char>(c - 'a' + 10);
809
 
    return static_cast<unsigned char>(c - 'A' + 10);
810
 
}
811
 
 
812
 
unsigned char Lexer::convertHex(int c1, int c2)
813
 
{
814
 
    return ((convertHex(c1) << 4) + convertHex(c2));
815
 
}
816
 
 
817
 
UChar Lexer::convertUnicode(int c1, int c2, int c3, int c4)
818
 
{
819
 
    unsigned char highByte = (convertHex(c1) << 4) + convertHex(c2);
820
 
    unsigned char lowByte = (convertHex(c3) << 4) + convertHex(c4);
821
 
    return (highByte << 8 | lowByte);
822
 
}
823
 
 
824
 
void Lexer::record8(int c)
825
 
{
826
 
    ASSERT(c >= 0);
827
 
    ASSERT(c <= 0xff);
828
 
    m_buffer8.append(static_cast<char>(c));
829
 
}
830
 
 
831
 
void Lexer::record16(int c)
832
 
{
833
 
    ASSERT(c >= 0);
834
 
    ASSERT(c <= USHRT_MAX);
835
 
    record16(UChar(static_cast<unsigned short>(c)));
836
 
}
837
 
 
838
 
void Lexer::record16(UChar c)
839
 
{
840
 
    m_buffer16.append(c);
841
 
}
842
 
 
843
 
bool Lexer::scanRegExp()
844
 
{
845
 
    m_buffer16.clear();
 
552
            if (isIdentStart(m_current))
 
553
                goto startIdentifierOrKeyword;
 
554
            if (isLineTerminator(m_current)) {
 
555
                shiftLineTerminator();
 
556
                m_atLineStart = true;
 
557
                m_terminator = true;
 
558
                if (lastTokenWasRestrKeyword()) {
 
559
                    token = ';';
 
560
                    goto doneSemicolon;
 
561
                }
 
562
                goto start;
 
563
            }
 
564
            goto returnError;
 
565
    }
 
566
 
 
567
    m_atLineStart = false;
 
568
    goto returnToken;
 
569
 
 
570
startString: {
 
571
    int stringQuoteCharacter = m_current;
 
572
    shift1();
 
573
 
 
574
    const UChar* stringStart = currentCharacter();
 
575
    while (m_current != stringQuoteCharacter) {
 
576
        // Fast check for characters that require special handling.
 
577
        // Catches -1, \n, \r, \, 0x2028, and 0x2029 as efficiently
 
578
        // as possible, and lets through all common ASCII characters.
 
579
        if (UNLIKELY(m_current == '\\') || UNLIKELY(((static_cast<unsigned>(m_current) - 0xE) & 0x2000))) {
 
580
            m_buffer16.append(stringStart, currentCharacter() - stringStart);
 
581
            goto inString;
 
582
        }
 
583
        shift1();
 
584
    }
 
585
    lvalp->ident = makeIdentifier(stringStart, currentCharacter() - stringStart);
 
586
    shift1();
 
587
    m_atLineStart = false;
 
588
    m_delimited = false;
 
589
    token = STRING;
 
590
    goto returnToken;
 
591
 
 
592
inString:
 
593
    while (m_current != stringQuoteCharacter) {
 
594
        if (m_current == '\\')
 
595
            goto inStringEscapeSequence;
 
596
        if (UNLIKELY(isLineTerminator(m_current)))
 
597
            goto returnError;
 
598
        if (UNLIKELY(m_current == -1))
 
599
            goto returnError;
 
600
        record16(m_current);
 
601
        shift1();
 
602
    }
 
603
    goto doneString;
 
604
 
 
605
inStringEscapeSequence:
 
606
    shift1();
 
607
    if (m_current == 'x') {
 
608
        shift1();
 
609
        if (isASCIIHexDigit(m_current) && isASCIIHexDigit(m_next1)) {
 
610
            record16(convertHex(m_current, m_next1));
 
611
            shift2();
 
612
            goto inString;
 
613
        }
 
614
        record16('x');
 
615
        if (m_current == stringQuoteCharacter)
 
616
            goto doneString;
 
617
        goto inString;
 
618
    }
 
619
    if (m_current == 'u') {
 
620
        shift1();
 
621
        if (isASCIIHexDigit(m_current) && isASCIIHexDigit(m_next1) && isASCIIHexDigit(m_next2) && isASCIIHexDigit(m_next3)) {
 
622
            record16(convertUnicode(m_current, m_next1, m_next2, m_next3));
 
623
            shift4();
 
624
            goto inString;
 
625
        }
 
626
        if (m_current == stringQuoteCharacter) {
 
627
            record16('u');
 
628
            goto doneString;
 
629
        }
 
630
        goto returnError;
 
631
    }
 
632
    if (isASCIIOctalDigit(m_current)) {
 
633
        if (m_current >= '0' && m_current <= '3' && isASCIIOctalDigit(m_next1) && isASCIIOctalDigit(m_next2)) {
 
634
            record16((m_current - '0') * 64 + (m_next1 - '0') * 8 + m_next2 - '0');
 
635
            shift3();
 
636
            goto inString;
 
637
        }
 
638
        if (isASCIIOctalDigit(m_next1)) {
 
639
            record16((m_current - '0') * 8 + m_next1 - '0');
 
640
            shift2();
 
641
            goto inString;
 
642
        }
 
643
        record16(m_current - '0');
 
644
        shift1();
 
645
        goto inString;
 
646
    }
 
647
    if (isLineTerminator(m_current)) {
 
648
        shiftLineTerminator();
 
649
        goto inString;
 
650
    }
 
651
    record16(singleEscape(m_current));
 
652
    shift1();
 
653
    goto inString;
 
654
}
 
655
 
 
656
startIdentifierWithBackslash:
 
657
    shift1();
 
658
    if (UNLIKELY(m_current != 'u'))
 
659
        goto returnError;
 
660
    shift1();
 
661
    if (UNLIKELY(!isASCIIHexDigit(m_current) || !isASCIIHexDigit(m_next1) || !isASCIIHexDigit(m_next2) || !isASCIIHexDigit(m_next3)))
 
662
        goto returnError;
 
663
    token = convertUnicode(m_current, m_next1, m_next2, m_next3);
 
664
    if (UNLIKELY(!isIdentStart(token)))
 
665
        goto returnError;
 
666
    goto inIdentifierAfterCharacterCheck;
 
667
 
 
668
startIdentifierOrKeyword: {
 
669
    const UChar* identifierStart = currentCharacter();
 
670
    shift1();
 
671
    while (isIdentPart(m_current))
 
672
        shift1();
 
673
    if (LIKELY(m_current != '\\')) {
 
674
        lvalp->ident = makeIdentifier(identifierStart, currentCharacter() - identifierStart);
 
675
        goto doneIdentifierOrKeyword;
 
676
    }
 
677
    m_buffer16.append(identifierStart, currentCharacter() - identifierStart);
 
678
}
 
679
 
 
680
    do {
 
681
        shift1();
 
682
        if (UNLIKELY(m_current != 'u'))
 
683
            goto returnError;
 
684
        shift1();
 
685
        if (UNLIKELY(!isASCIIHexDigit(m_current) || !isASCIIHexDigit(m_next1) || !isASCIIHexDigit(m_next2) || !isASCIIHexDigit(m_next3)))
 
686
            goto returnError;
 
687
        token = convertUnicode(m_current, m_next1, m_next2, m_next3);
 
688
        if (UNLIKELY(!isIdentPart(token)))
 
689
            goto returnError;
 
690
inIdentifierAfterCharacterCheck:
 
691
        record16(token);
 
692
        shift4();
 
693
 
 
694
        while (isIdentPart(m_current)) {
 
695
            record16(m_current);
 
696
            shift1();
 
697
        }
 
698
    } while (UNLIKELY(m_current == '\\'));
 
699
    goto doneIdentifier;
 
700
 
 
701
inSingleLineComment:
 
702
    while (!isLineTerminator(m_current)) {
 
703
        if (UNLIKELY(m_current == -1))
 
704
            return 0;
 
705
        shift1();
 
706
    }
 
707
    shiftLineTerminator();
 
708
    m_atLineStart = true;
 
709
    m_terminator = true;
 
710
    if (lastTokenWasRestrKeyword())
 
711
        goto doneSemicolon;
 
712
    goto start;
 
713
 
 
714
inMultiLineComment:
 
715
    shift2();
 
716
    while (m_current != '*' || m_next1 != '/') {
 
717
        if (isLineTerminator(m_current))
 
718
            shiftLineTerminator();
 
719
        else {
 
720
            shift1();
 
721
            if (UNLIKELY(m_current == -1))
 
722
                goto returnError;
 
723
        }
 
724
    }
 
725
    shift2();
 
726
    m_atLineStart = false;
 
727
    goto start;
 
728
 
 
729
startNumberWithZeroDigit:
 
730
    shift1();
 
731
    if ((m_current | 0x20) == 'x' && isASCIIHexDigit(m_next1)) {
 
732
        shift1();
 
733
        goto inHex;
 
734
    }
 
735
    if (m_current == '.') {
 
736
        record8('0');
 
737
        record8('.');
 
738
        shift1();
 
739
        goto inNumberAfterDecimalPoint;
 
740
    }
 
741
    if ((m_current | 0x20) == 'e') {
 
742
        record8('0');
 
743
        record8('e');
 
744
        shift1();
 
745
        goto inExponentIndicator;
 
746
    }
 
747
    if (isASCIIOctalDigit(m_current))
 
748
        goto inOctal;
 
749
    if (isASCIIDigit(m_current))
 
750
        goto startNumber;
 
751
    lvalp->doubleValue = 0;
 
752
    goto doneNumeric;
 
753
 
 
754
inNumberAfterDecimalPoint:
 
755
    while (isASCIIDigit(m_current)) {
 
756
        record8(m_current);
 
757
        shift1();
 
758
    }
 
759
    if ((m_current | 0x20) == 'e') {
 
760
        record8('e');
 
761
        shift1();
 
762
        goto inExponentIndicator;
 
763
    }
 
764
    goto doneNumber;
 
765
 
 
766
inExponentIndicator:
 
767
    if (m_current == '+' || m_current == '-') {
 
768
        record8(m_current);
 
769
        shift1();
 
770
    }
 
771
    if (!isASCIIDigit(m_current))
 
772
        goto returnError;
 
773
    do {
 
774
        record8(m_current);
 
775
        shift1();
 
776
    } while (isASCIIDigit(m_current));
 
777
    goto doneNumber;
 
778
 
 
779
inOctal: {
 
780
    do {
 
781
        record8(m_current);
 
782
        shift1();
 
783
    } while (isASCIIOctalDigit(m_current));
 
784
    if (isASCIIDigit(m_current))
 
785
        goto startNumber;
 
786
 
 
787
    double dval = 0;
 
788
 
 
789
    const char* end = m_buffer8.end();
 
790
    for (const char* p = m_buffer8.data(); p < end; ++p) {
 
791
        dval *= 8;
 
792
        dval += *p - '0';
 
793
    }
 
794
    if (dval >= mantissaOverflowLowerBound)
 
795
        dval = parseIntOverflow(m_buffer8.data(), end - m_buffer8.data(), 8);
 
796
 
 
797
    m_buffer8.resize(0);
 
798
 
 
799
    lvalp->doubleValue = dval;
 
800
    goto doneNumeric;
 
801
}
 
802
 
 
803
inHex: {
 
804
    do {
 
805
        record8(m_current);
 
806
        shift1();
 
807
    } while (isASCIIHexDigit(m_current));
 
808
 
 
809
    double dval = 0;
 
810
 
 
811
    const char* end = m_buffer8.end();
 
812
    for (const char* p = m_buffer8.data(); p < end; ++p) {
 
813
        dval *= 16;
 
814
        dval += toASCIIHexValue(*p);
 
815
    }
 
816
    if (dval >= mantissaOverflowLowerBound)
 
817
        dval = parseIntOverflow(m_buffer8.data(), end - m_buffer8.data(), 16);
 
818
 
 
819
    m_buffer8.resize(0);
 
820
 
 
821
    lvalp->doubleValue = dval;
 
822
    goto doneNumeric;
 
823
}
 
824
 
 
825
startNumber:
 
826
    record8(m_current);
 
827
    shift1();
 
828
    while (isASCIIDigit(m_current)) {
 
829
        record8(m_current);
 
830
        shift1();
 
831
    }
 
832
    if (m_current == '.') {
 
833
        record8('.');
 
834
        shift1();
 
835
        goto inNumberAfterDecimalPoint;
 
836
    }
 
837
    if ((m_current | 0x20) == 'e') {
 
838
        record8('e');
 
839
        shift1();
 
840
        goto inExponentIndicator;
 
841
    }
 
842
 
 
843
    // Fall through into doneNumber.
 
844
 
 
845
doneNumber:
 
846
    // Null-terminate string for strtod.
 
847
    m_buffer8.append('\0');
 
848
    lvalp->doubleValue = WTF::strtod(m_buffer8.data(), 0);
 
849
    m_buffer8.resize(0);
 
850
 
 
851
    // Fall through into doneNumeric.
 
852
 
 
853
doneNumeric:
 
854
    // No identifiers allowed directly after numeric literal, e.g. "3in" is bad.
 
855
    if (UNLIKELY(isIdentStart(m_current)))
 
856
        goto returnError;
 
857
 
 
858
    m_atLineStart = false;
 
859
    m_delimited = false;
 
860
    token = NUMBER;
 
861
    goto returnToken;
 
862
 
 
863
doneSemicolon:
 
864
    token = ';';
 
865
    m_delimited = true;
 
866
    goto returnToken;
 
867
 
 
868
doneIdentifier:
 
869
    m_atLineStart = false;
 
870
    m_delimited = false;
 
871
    lvalp->ident = makeIdentifier(m_buffer16.data(), m_buffer16.size());
 
872
    m_buffer16.resize(0);
 
873
    token = IDENT;
 
874
    goto returnToken;
 
875
 
 
876
doneIdentifierOrKeyword: {
 
877
    m_atLineStart = false;
 
878
    m_delimited = false;
 
879
    m_buffer16.resize(0);
 
880
    const HashEntry* entry = m_keywordTable.entry(m_globalData, *lvalp->ident);
 
881
    token = entry ? entry->lexerValue() : IDENT;
 
882
    goto returnToken;
 
883
}
 
884
 
 
885
doneString:
 
886
    // Atomize constant strings in case they're later used in property lookup.
 
887
    shift1();
 
888
    m_atLineStart = false;
 
889
    m_delimited = false;
 
890
    lvalp->ident = makeIdentifier(m_buffer16.data(), m_buffer16.size());
 
891
    m_buffer16.resize(0);
 
892
    token = STRING;
 
893
 
 
894
    // Fall through into returnToken.
 
895
 
 
896
returnToken: {
 
897
    int lineNumber = m_lineNumber;
 
898
    llocp->first_line = lineNumber;
 
899
    llocp->last_line = lineNumber;
 
900
    llocp->first_column = startOffset;
 
901
    llocp->last_column = currentOffset();
 
902
 
 
903
    m_lastToken = token;
 
904
    return token;
 
905
}
 
906
 
 
907
returnError:
 
908
    m_error = true;
 
909
    return -1;
 
910
}
 
911
 
 
912
bool Lexer::scanRegExp(const Identifier*& pattern, const Identifier*& flags, UChar prefix)
 
913
{
 
914
    ASSERT(m_buffer16.isEmpty());
 
915
 
846
916
    bool lastWasEscape = false;
847
917
    bool inBrackets = false;
848
918
 
849
 
    while (1) {
850
 
        if (isLineTerminator() || m_current == -1)
 
919
    if (prefix)
 
920
        record16(prefix);
 
921
 
 
922
    while (true) {
 
923
        if (isLineTerminator(m_current) || m_current == -1) {
 
924
            m_buffer16.resize(0);
851
925
            return false;
852
 
        else if (m_current != '/' || lastWasEscape == true || inBrackets == true) {
 
926
        }
 
927
        if (m_current != '/' || lastWasEscape || inBrackets) {
853
928
            // keep track of '[' and ']'
854
929
            if (!lastWasEscape) {
855
 
                if ( m_current == '[' && !inBrackets )
 
930
                if (m_current == '[' && !inBrackets)
856
931
                    inBrackets = true;
857
 
                if ( m_current == ']' && inBrackets )
 
932
                if (m_current == ']' && inBrackets)
858
933
                    inBrackets = false;
859
934
            }
860
935
            record16(m_current);
861
 
            lastWasEscape =
862
 
            !lastWasEscape && (m_current == '\\');
 
936
            lastWasEscape = !lastWasEscape && m_current == '\\';
863
937
        } else { // end of regexp
864
 
            m_pattern = UString(m_buffer16);
865
 
            m_buffer16.clear();
866
 
            shift(1);
 
938
            pattern = makeIdentifier(m_buffer16.data(), m_buffer16.size());
 
939
            m_buffer16.resize(0);
 
940
            shift1();
867
941
            break;
868
942
        }
869
 
        shift(1);
 
943
        shift1();
870
944
    }
871
945
 
872
946
    while (isIdentPart(m_current)) {
873
947
        record16(m_current);
874
 
        shift(1);
875
 
    }
876
 
    m_flags = UString(m_buffer16);
 
948
        shift1();
 
949
    }
 
950
    flags = makeIdentifier(m_buffer16.data(), m_buffer16.size());
 
951
    m_buffer16.resize(0);
 
952
 
 
953
    return true;
 
954
}
 
955
 
 
956
bool Lexer::skipRegExp()
 
957
{
 
958
    bool lastWasEscape = false;
 
959
    bool inBrackets = false;
 
960
 
 
961
    while (true) {
 
962
        if (isLineTerminator(m_current) || m_current == -1)
 
963
            return false;
 
964
        if (m_current != '/' || lastWasEscape || inBrackets) {
 
965
            // keep track of '[' and ']'
 
966
            if (!lastWasEscape) {
 
967
                if (m_current == '[' && !inBrackets)
 
968
                    inBrackets = true;
 
969
                if (m_current == ']' && inBrackets)
 
970
                    inBrackets = false;
 
971
            }
 
972
            lastWasEscape = !lastWasEscape && m_current == '\\';
 
973
        } else { // end of regexp
 
974
            shift1();
 
975
            break;
 
976
        }
 
977
        shift1();
 
978
    }
 
979
 
 
980
    while (isIdentPart(m_current))
 
981
        shift1();
877
982
 
878
983
    return true;
879
984
}
880
985
 
881
986
void Lexer::clear()
882
987
{
883
 
    m_identifiers.clear();
 
988
    m_arena = 0;
 
989
    m_codeWithoutBOMs.clear();
884
990
 
885
991
    Vector<char> newBuffer8;
886
992
    newBuffer8.reserveInitialCapacity(initialReadBufferCapacity);
891
997
    m_buffer16.swap(newBuffer16);
892
998
 
893
999
    m_isReparsing = false;
894
 
 
895
 
    m_pattern = 0;
896
 
    m_flags = 0;
 
1000
}
 
1001
 
 
1002
SourceCode Lexer::sourceCode(int openBrace, int closeBrace, int firstLine)
 
1003
{
 
1004
    if (m_codeWithoutBOMs.isEmpty())
 
1005
        return SourceCode(m_source->provider(), openBrace, closeBrace + 1, firstLine);
 
1006
 
 
1007
    const UChar* data = m_source->provider()->data();
 
1008
 
 
1009
    ASSERT(openBrace < closeBrace);
 
1010
 
 
1011
    int numBOMsBeforeOpenBrace = 0;
 
1012
    int numBOMsBetweenBraces = 0;
 
1013
 
 
1014
    int i;
 
1015
    for (i = m_source->startOffset(); i < openBrace; ++i)
 
1016
        numBOMsBeforeOpenBrace += data[i] == byteOrderMark;
 
1017
    for (; i < closeBrace; ++i)
 
1018
        numBOMsBetweenBraces += data[i] == byteOrderMark;
 
1019
 
 
1020
    return SourceCode(m_source->provider(), openBrace + numBOMsBeforeOpenBrace,
 
1021
        closeBrace + numBOMsBeforeOpenBrace + numBOMsBetweenBraces + 1, firstLine);
897
1022
}
898
1023
 
899
1024
} // namespace JSC