]> git.saurik.com Git - apple/javascriptcore.git/blame - runtime/LiteralParser.cpp
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / runtime / LiteralParser.cpp
CommitLineData
ba379fdc
A
1/*
2 * Copyright (C) 2009 Apple Inc. All rights reserved.
6fe7ccc8 3 * Copyright (C) 2012 Mathias Bynens (mathias@qiwi.be)
ba379fdc
A
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include "config.h"
28#include "LiteralParser.h"
29
93a37866
A
30#include "ButterflyInlines.h"
31#include "CopiedSpaceInlines.h"
ba379fdc
A
32#include "JSArray.h"
33#include "JSString.h"
34#include "Lexer.h"
93a37866 35#include "ObjectConstructor.h"
81345200 36#include "JSCInlines.h"
6fe7ccc8 37#include "StrongInlines.h"
ba379fdc
A
38#include <wtf/ASCIICType.h>
39#include <wtf/dtoa.h>
93a37866 40#include <wtf/text/StringBuilder.h>
ba379fdc
A
41
42namespace JSC {
43
6fe7ccc8
A
44template <typename CharType>
45static inline bool isJSONWhiteSpace(const CharType& c)
ba379fdc 46{
14957cd0
A
47 // The JSON RFC 4627 defines a list of allowed characters to be considered
48 // insignificant white space: http://www.ietf.org/rfc/rfc4627.txt (2. JSON Grammar).
49 return c == ' ' || c == 0x9 || c == 0xA || c == 0xD;
50}
51
6fe7ccc8
A
52template <typename CharType>
53bool LiteralParser<CharType>::tryJSONPParse(Vector<JSONPData>& results, bool needsFullSourceInfo)
14957cd0
A
54{
55 if (m_lexer.next() != TokIdentifier)
56 return false;
57 do {
58 Vector<JSONPPathEntry> path;
59 // Unguarded next to start off the lexer
ed1e77d3 60 Identifier name = Identifier::fromString(&m_exec->vm(), m_lexer.currentToken().start, m_lexer.currentToken().end - m_lexer.currentToken().start);
14957cd0 61 JSONPPathEntry entry;
93a37866 62 if (name == m_exec->vm().propertyNames->varKeyword) {
14957cd0
A
63 if (m_lexer.next() != TokIdentifier)
64 return false;
65 entry.m_type = JSONPPathEntryTypeDeclare;
ed1e77d3 66 entry.m_pathEntryName = Identifier::fromString(&m_exec->vm(), m_lexer.currentToken().start, m_lexer.currentToken().end - m_lexer.currentToken().start);
14957cd0
A
67 path.append(entry);
68 } else {
69 entry.m_type = JSONPPathEntryTypeDot;
ed1e77d3 70 entry.m_pathEntryName = Identifier::fromString(&m_exec->vm(), m_lexer.currentToken().start, m_lexer.currentToken().end - m_lexer.currentToken().start);
14957cd0
A
71 path.append(entry);
72 }
93a37866 73 if (m_exec->vm().keywords->isKeyword(entry.m_pathEntryName))
14957cd0
A
74 return false;
75 TokenType tokenType = m_lexer.next();
93a37866
A
76 if (entry.m_type == JSONPPathEntryTypeDeclare && tokenType != TokAssign)
77 return false;
14957cd0
A
78 while (tokenType != TokAssign) {
79 switch (tokenType) {
80 case TokLBracket: {
81 entry.m_type = JSONPPathEntryTypeLookup;
82 if (m_lexer.next() != TokNumber)
83 return false;
84 double doubleIndex = m_lexer.currentToken().numberToken;
85 int index = (int)doubleIndex;
86 if (index != doubleIndex || index < 0)
87 return false;
88 entry.m_pathIndex = index;
89 if (m_lexer.next() != TokRBracket)
90 return false;
91 break;
92 }
93 case TokDot: {
94 entry.m_type = JSONPPathEntryTypeDot;
95 if (m_lexer.next() != TokIdentifier)
96 return false;
ed1e77d3 97 entry.m_pathEntryName = Identifier::fromString(&m_exec->vm(), m_lexer.currentToken().start, m_lexer.currentToken().end - m_lexer.currentToken().start);
14957cd0
A
98 break;
99 }
100 case TokLParen: {
101 if (path.last().m_type != JSONPPathEntryTypeDot || needsFullSourceInfo)
102 return false;
103 path.last().m_type = JSONPPathEntryTypeCall;
104 entry = path.last();
105 goto startJSON;
106 }
107 default:
108 return false;
109 }
110 path.append(entry);
111 tokenType = m_lexer.next();
112 }
113 startJSON:
114 m_lexer.next();
115 results.append(JSONPData());
93a37866 116 results.last().m_value.set(m_exec->vm(), parse(StartParseExpression));
14957cd0
A
117 if (!results.last().m_value)
118 return false;
119 results.last().m_path.swap(path);
120 if (entry.m_type == JSONPPathEntryTypeCall) {
121 if (m_lexer.currentToken().type != TokRParen)
122 return false;
123 m_lexer.next();
124 }
125 if (m_lexer.currentToken().type != TokSemi)
126 break;
127 m_lexer.next();
128 } while (m_lexer.currentToken().type == TokIdentifier);
129 return m_lexer.currentToken().type == TokEnd;
130}
131
6fe7ccc8
A
132template <typename CharType>
133ALWAYS_INLINE const Identifier LiteralParser<CharType>::makeIdentifier(const LChar* characters, size_t length)
14957cd0
A
134{
135 if (!length)
93a37866 136 return m_exec->vm().propertyNames->emptyIdentifier;
14957cd0 137 if (characters[0] >= MaximumCachableCharacter)
ed1e77d3 138 return Identifier::fromString(&m_exec->vm(), characters, length);
14957cd0
A
139
140 if (length == 1) {
141 if (!m_shortIdentifiers[characters[0]].isNull())
142 return m_shortIdentifiers[characters[0]];
ed1e77d3 143 m_shortIdentifiers[characters[0]] = Identifier::fromString(&m_exec->vm(), characters, length);
14957cd0
A
144 return m_shortIdentifiers[characters[0]];
145 }
146 if (!m_recentIdentifiers[characters[0]].isNull() && Identifier::equal(m_recentIdentifiers[characters[0]].impl(), characters, length))
147 return m_recentIdentifiers[characters[0]];
ed1e77d3 148 m_recentIdentifiers[characters[0]] = Identifier::fromString(&m_exec->vm(), characters, length);
14957cd0
A
149 return m_recentIdentifiers[characters[0]];
150}
151
6fe7ccc8
A
152template <typename CharType>
153ALWAYS_INLINE const Identifier LiteralParser<CharType>::makeIdentifier(const UChar* characters, size_t length)
154{
155 if (!length)
93a37866 156 return m_exec->vm().propertyNames->emptyIdentifier;
6fe7ccc8 157 if (characters[0] >= MaximumCachableCharacter)
ed1e77d3 158 return Identifier::fromString(&m_exec->vm(), characters, length);
6fe7ccc8
A
159
160 if (length == 1) {
161 if (!m_shortIdentifiers[characters[0]].isNull())
162 return m_shortIdentifiers[characters[0]];
ed1e77d3 163 m_shortIdentifiers[characters[0]] = Identifier::fromString(&m_exec->vm(), characters, length);
6fe7ccc8
A
164 return m_shortIdentifiers[characters[0]];
165 }
166 if (!m_recentIdentifiers[characters[0]].isNull() && Identifier::equal(m_recentIdentifiers[characters[0]].impl(), characters, length))
167 return m_recentIdentifiers[characters[0]];
ed1e77d3 168 m_recentIdentifiers[characters[0]] = Identifier::fromString(&m_exec->vm(), characters, length);
6fe7ccc8
A
169 return m_recentIdentifiers[characters[0]];
170}
171
172template <typename CharType>
173template <ParserMode mode> TokenType LiteralParser<CharType>::Lexer::lex(LiteralParserToken<CharType>& token)
14957cd0
A
174{
175 while (m_ptr < m_end && isJSONWhiteSpace(*m_ptr))
ba379fdc
A
176 ++m_ptr;
177
178 ASSERT(m_ptr <= m_end);
179 if (m_ptr >= m_end) {
180 token.type = TokEnd;
181 token.start = token.end = m_ptr;
182 return TokEnd;
183 }
184 token.type = TokError;
185 token.start = m_ptr;
186 switch (*m_ptr) {
187 case '[':
188 token.type = TokLBracket;
189 token.end = ++m_ptr;
190 return TokLBracket;
191 case ']':
192 token.type = TokRBracket;
193 token.end = ++m_ptr;
194 return TokRBracket;
195 case '(':
196 token.type = TokLParen;
197 token.end = ++m_ptr;
14957cd0 198 return TokLParen;
ba379fdc
A
199 case ')':
200 token.type = TokRParen;
201 token.end = ++m_ptr;
14957cd0 202 return TokRParen;
ba379fdc
A
203 case '{':
204 token.type = TokLBrace;
205 token.end = ++m_ptr;
206 return TokLBrace;
207 case '}':
208 token.type = TokRBrace;
209 token.end = ++m_ptr;
210 return TokRBrace;
211 case ',':
212 token.type = TokComma;
213 token.end = ++m_ptr;
214 return TokComma;
215 case ':':
216 token.type = TokColon;
217 token.end = ++m_ptr;
218 return TokColon;
219 case '"':
14957cd0 220 return lexString<mode, '"'>(token);
ba379fdc
A
221 case 't':
222 if (m_end - m_ptr >= 4 && m_ptr[1] == 'r' && m_ptr[2] == 'u' && m_ptr[3] == 'e') {
223 m_ptr += 4;
224 token.type = TokTrue;
225 token.end = m_ptr;
226 return TokTrue;
227 }
228 break;
229 case 'f':
230 if (m_end - m_ptr >= 5 && m_ptr[1] == 'a' && m_ptr[2] == 'l' && m_ptr[3] == 's' && m_ptr[4] == 'e') {
231 m_ptr += 5;
232 token.type = TokFalse;
233 token.end = m_ptr;
234 return TokFalse;
235 }
236 break;
237 case 'n':
238 if (m_end - m_ptr >= 4 && m_ptr[1] == 'u' && m_ptr[2] == 'l' && m_ptr[3] == 'l') {
239 m_ptr += 4;
240 token.type = TokNull;
241 token.end = m_ptr;
242 return TokNull;
243 }
14957cd0 244 break;
ba379fdc
A
245 case '-':
246 case '0':
247 case '1':
248 case '2':
249 case '3':
250 case '4':
251 case '5':
252 case '6':
253 case '7':
254 case '8':
255 case '9':
256 return lexNumber(token);
257 }
14957cd0
A
258 if (m_ptr < m_end) {
259 if (*m_ptr == '.') {
260 token.type = TokDot;
261 token.end = ++m_ptr;
262 return TokDot;
263 }
264 if (*m_ptr == '=') {
265 token.type = TokAssign;
266 token.end = ++m_ptr;
267 return TokAssign;
268 }
269 if (*m_ptr == ';') {
270 token.type = TokSemi;
271 token.end = ++m_ptr;
272 return TokAssign;
273 }
6fe7ccc8
A
274 if (isASCIIAlpha(*m_ptr) || *m_ptr == '_' || *m_ptr == '$')
275 return lexIdentifier(token);
14957cd0 276 if (*m_ptr == '\'') {
6fe7ccc8 277 if (mode == StrictJSON) {
93a37866 278 m_lexErrorMessage = ASCIILiteral("Single quotes (\') are not allowed in JSON");
14957cd0 279 return TokError;
6fe7ccc8 280 }
14957cd0
A
281 return lexString<mode, '\''>(token);
282 }
283 }
ed1e77d3 284 m_lexErrorMessage = String::format("Unrecognized token '%c'", *m_ptr);
ba379fdc
A
285 return TokError;
286}
287
6fe7ccc8
A
288template <>
289ALWAYS_INLINE TokenType LiteralParser<LChar>::Lexer::lexIdentifier(LiteralParserToken<LChar>& token)
290{
291 while (m_ptr < m_end && (isASCIIAlphanumeric(*m_ptr) || *m_ptr == '_' || *m_ptr == '$'))
292 m_ptr++;
293 token.stringIs8Bit = 1;
294 token.stringToken8 = token.start;
295 token.stringLength = m_ptr - token.start;
296 token.type = TokIdentifier;
297 token.end = m_ptr;
298 return TokIdentifier;
299}
300
301template <>
302ALWAYS_INLINE TokenType LiteralParser<UChar>::Lexer::lexIdentifier(LiteralParserToken<UChar>& token)
303{
304 while (m_ptr < m_end && (isASCIIAlphanumeric(*m_ptr) || *m_ptr == '_' || *m_ptr == '$' || *m_ptr == 0x200C || *m_ptr == 0x200D))
305 m_ptr++;
306 token.stringIs8Bit = 0;
307 token.stringToken16 = token.start;
308 token.stringLength = m_ptr - token.start;
309 token.type = TokIdentifier;
310 token.end = m_ptr;
311 return TokIdentifier;
312}
313
314template <typename CharType>
315TokenType LiteralParser<CharType>::Lexer::next()
14957cd0
A
316{
317 if (m_mode == NonStrictJSON)
318 return lex<NonStrictJSON>(m_currentToken);
319 if (m_mode == JSONP)
320 return lex<JSONP>(m_currentToken);
321 return lex<StrictJSON>(m_currentToken);
322}
323
6fe7ccc8
A
324template <>
325ALWAYS_INLINE void setParserTokenString<LChar>(LiteralParserToken<LChar>& token, const LChar* string)
ba379fdc 326{
6fe7ccc8
A
327 token.stringIs8Bit = 1;
328 token.stringToken8 = string;
ba379fdc
A
329}
330
6fe7ccc8
A
331template <>
332ALWAYS_INLINE void setParserTokenString<UChar>(LiteralParserToken<UChar>& token, const UChar* string)
333{
334 token.stringIs8Bit = 0;
335 token.stringToken16 = string;
336}
337
338template <ParserMode mode, typename CharType, LChar terminator> static inline bool isSafeStringCharacter(LChar c)
339{
340 return (c >= ' ' && c != '\\' && c != terminator) || (c == '\t' && mode != StrictJSON);
341}
342
343template <ParserMode mode, typename CharType, UChar terminator> static inline bool isSafeStringCharacter(UChar c)
344{
345 return (c >= ' ' && (mode == StrictJSON || c <= 0xff) && c != '\\' && c != terminator) || (c == '\t' && mode != StrictJSON);
346}
347
348template <typename CharType>
349template <ParserMode mode, char terminator> ALWAYS_INLINE TokenType LiteralParser<CharType>::Lexer::lexString(LiteralParserToken<CharType>& token)
ba379fdc
A
350{
351 ++m_ptr;
6fe7ccc8 352 const CharType* runStart = m_ptr;
93a37866 353 StringBuilder builder;
ba379fdc
A
354 do {
355 runStart = m_ptr;
6fe7ccc8 356 while (m_ptr < m_end && isSafeStringCharacter<mode, CharType, terminator>(*m_ptr))
ba379fdc 357 ++m_ptr;
14957cd0 358 if (builder.length())
f9bf01c6 359 builder.append(runStart, m_ptr - runStart);
14957cd0
A
360 if ((mode != NonStrictJSON) && m_ptr < m_end && *m_ptr == '\\') {
361 if (builder.isEmpty() && runStart < m_ptr)
362 builder.append(runStart, m_ptr - runStart);
ba379fdc 363 ++m_ptr;
6fe7ccc8 364 if (m_ptr >= m_end) {
93a37866 365 m_lexErrorMessage = ASCIILiteral("Unterminated string");
ba379fdc 366 return TokError;
6fe7ccc8 367 }
ba379fdc
A
368 switch (*m_ptr) {
369 case '"':
f9bf01c6 370 builder.append('"');
ba379fdc
A
371 m_ptr++;
372 break;
373 case '\\':
f9bf01c6 374 builder.append('\\');
ba379fdc
A
375 m_ptr++;
376 break;
377 case '/':
f9bf01c6 378 builder.append('/');
ba379fdc
A
379 m_ptr++;
380 break;
381 case 'b':
f9bf01c6 382 builder.append('\b');
ba379fdc
A
383 m_ptr++;
384 break;
385 case 'f':
f9bf01c6 386 builder.append('\f');
ba379fdc
A
387 m_ptr++;
388 break;
389 case 'n':
f9bf01c6 390 builder.append('\n');
ba379fdc
A
391 m_ptr++;
392 break;
393 case 'r':
f9bf01c6 394 builder.append('\r');
ba379fdc
A
395 m_ptr++;
396 break;
397 case 't':
f9bf01c6 398 builder.append('\t');
ba379fdc
A
399 m_ptr++;
400 break;
401
402 case 'u':
6fe7ccc8 403 if ((m_end - m_ptr) < 5) {
93a37866 404 m_lexErrorMessage = ASCIILiteral("\\u must be followed by 4 hex digits");
ba379fdc 405 return TokError;
6fe7ccc8 406 } // uNNNN == 5 characters
ba379fdc 407 for (int i = 1; i < 5; i++) {
6fe7ccc8 408 if (!isASCIIHexDigit(m_ptr[i])) {
ed1e77d3 409 m_lexErrorMessage = String::format("\"\\%s\" is not a valid unicode escape", String(m_ptr, 5).ascii().data());
ba379fdc 410 return TokError;
6fe7ccc8 411 }
ba379fdc 412 }
6fe7ccc8 413 builder.append(JSC::Lexer<CharType>::convertUnicode(m_ptr[1], m_ptr[2], m_ptr[3], m_ptr[4]));
ba379fdc
A
414 m_ptr += 5;
415 break;
416
417 default:
14957cd0
A
418 if (*m_ptr == '\'' && mode != StrictJSON) {
419 builder.append('\'');
420 m_ptr++;
421 break;
422 }
ed1e77d3 423 m_lexErrorMessage = String::format("Invalid escape character %c", *m_ptr);
ba379fdc
A
424 return TokError;
425 }
426 }
14957cd0 427 } while ((mode != NonStrictJSON) && m_ptr != runStart && (m_ptr < m_end) && *m_ptr != terminator);
ba379fdc 428
6fe7ccc8 429 if (m_ptr >= m_end || *m_ptr != terminator) {
93a37866 430 m_lexErrorMessage = ASCIILiteral("Unterminated string");
ba379fdc 431 return TokError;
6fe7ccc8 432 }
ba379fdc 433
14957cd0 434 if (builder.isEmpty()) {
93a37866 435 token.stringBuffer = String();
6fe7ccc8 436 setParserTokenString<CharType>(token, runStart);
14957cd0
A
437 token.stringLength = m_ptr - runStart;
438 } else {
93a37866 439 token.stringBuffer = builder.toString();
6fe7ccc8
A
440 if (token.stringBuffer.is8Bit()) {
441 token.stringIs8Bit = 1;
442 token.stringToken8 = token.stringBuffer.characters8();
443 } else {
444 token.stringIs8Bit = 0;
445 token.stringToken16 = token.stringBuffer.characters16();
446 }
14957cd0
A
447 token.stringLength = token.stringBuffer.length();
448 }
ba379fdc
A
449 token.type = TokString;
450 token.end = ++m_ptr;
451 return TokString;
452}
453
6fe7ccc8
A
454template <typename CharType>
455TokenType LiteralParser<CharType>::Lexer::lexNumber(LiteralParserToken<CharType>& token)
ba379fdc
A
456{
457 // ES5 and json.org define numbers as
458 // number
459 // int
460 // int frac? exp?
461 //
462 // int
463 // -? 0
464 // -? digit1-9 digits?
465 //
466 // digits
467 // digit digits?
468 //
469 // -?(0 | [1-9][0-9]*) ('.' [0-9]+)? ([eE][+-]? [0-9]+)?
470
471 if (m_ptr < m_end && *m_ptr == '-') // -?
472 ++m_ptr;
473
474 // (0 | [1-9][0-9]*)
475 if (m_ptr < m_end && *m_ptr == '0') // 0
476 ++m_ptr;
477 else if (m_ptr < m_end && *m_ptr >= '1' && *m_ptr <= '9') { // [1-9]
478 ++m_ptr;
479 // [0-9]*
480 while (m_ptr < m_end && isASCIIDigit(*m_ptr))
481 ++m_ptr;
6fe7ccc8 482 } else {
93a37866 483 m_lexErrorMessage = ASCIILiteral("Invalid number");
ba379fdc 484 return TokError;
6fe7ccc8 485 }
ba379fdc
A
486
487 // ('.' [0-9]+)?
488 if (m_ptr < m_end && *m_ptr == '.') {
489 ++m_ptr;
490 // [0-9]+
6fe7ccc8 491 if (m_ptr >= m_end || !isASCIIDigit(*m_ptr)) {
93a37866 492 m_lexErrorMessage = ASCIILiteral("Invalid digits after decimal point");
ba379fdc 493 return TokError;
6fe7ccc8 494 }
ba379fdc
A
495
496 ++m_ptr;
497 while (m_ptr < m_end && isASCIIDigit(*m_ptr))
498 ++m_ptr;
14957cd0
A
499 } else if (m_ptr < m_end && (*m_ptr != 'e' && *m_ptr != 'E') && (m_ptr - token.start) < 10) {
500 int result = 0;
501 token.type = TokNumber;
502 token.end = m_ptr;
6fe7ccc8 503 const CharType* digit = token.start;
14957cd0
A
504 int negative = 1;
505 if (*digit == '-') {
506 negative = -1;
507 digit++;
508 }
509
510 while (digit < m_ptr)
511 result = result * 10 + (*digit++) - '0';
512 result *= negative;
513 token.numberToken = result;
514 return TokNumber;
ba379fdc
A
515 }
516
517 // ([eE][+-]? [0-9]+)?
518 if (m_ptr < m_end && (*m_ptr == 'e' || *m_ptr == 'E')) { // [eE]
519 ++m_ptr;
520
521 // [-+]?
522 if (m_ptr < m_end && (*m_ptr == '-' || *m_ptr == '+'))
523 ++m_ptr;
524
525 // [0-9]+
6fe7ccc8 526 if (m_ptr >= m_end || !isASCIIDigit(*m_ptr)) {
93a37866 527 m_lexErrorMessage = ASCIILiteral("Exponent symbols should be followed by an optional '+' or '-' and then by at least one number");
ba379fdc 528 return TokError;
6fe7ccc8 529 }
ba379fdc
A
530
531 ++m_ptr;
532 while (m_ptr < m_end && isASCIIDigit(*m_ptr))
533 ++m_ptr;
534 }
535
536 token.type = TokNumber;
537 token.end = m_ptr;
6fe7ccc8
A
538 size_t parsedLength;
539 token.numberToken = parseDouble(token.start, token.end - token.start, parsedLength);
ba379fdc
A
540 return TokNumber;
541}
542
6fe7ccc8
A
543template <typename CharType>
544JSValue LiteralParser<CharType>::parse(ParserState initialState)
ba379fdc
A
545{
546 ParserState state = initialState;
547 MarkedArgumentBuffer objectStack;
548 JSValue lastValue;
93a37866
A
549 Vector<ParserState, 16, UnsafeVectorOverflow> stateStack;
550 Vector<Identifier, 16, UnsafeVectorOverflow> identifierStack;
ed1e77d3 551 HashSet<JSObject*> visitedUnderscoreProto;
ba379fdc
A
552 while (1) {
553 switch(state) {
554 startParseArray:
555 case StartParseArray: {
93a37866 556 JSArray* array = constructEmptyArray(m_exec, 0);
ba379fdc 557 objectStack.append(array);
ba379fdc
A
558 }
559 doParseArrayStartExpression:
81345200 560 FALLTHROUGH;
ba379fdc 561 case DoParseArrayStartExpression: {
f9bf01c6 562 TokenType lastToken = m_lexer.currentToken().type;
ba379fdc 563 if (m_lexer.next() == TokRBracket) {
6fe7ccc8 564 if (lastToken == TokComma) {
93a37866 565 m_parseErrorMessage = ASCIILiteral("Unexpected comma at the end of array expression");
f9bf01c6 566 return JSValue();
6fe7ccc8 567 }
ba379fdc
A
568 m_lexer.next();
569 lastValue = objectStack.last();
570 objectStack.removeLast();
571 break;
572 }
573
574 stateStack.append(DoParseArrayEndExpression);
575 goto startParseExpression;
576 }
577 case DoParseArrayEndExpression: {
93a37866
A
578 JSArray* array = asArray(objectStack.last());
579 array->putDirectIndex(m_exec, array->length(), lastValue);
ba379fdc
A
580
581 if (m_lexer.currentToken().type == TokComma)
582 goto doParseArrayStartExpression;
583
6fe7ccc8 584 if (m_lexer.currentToken().type != TokRBracket) {
93a37866 585 m_parseErrorMessage = ASCIILiteral("Expected ']'");
ba379fdc 586 return JSValue();
6fe7ccc8 587 }
ba379fdc
A
588
589 m_lexer.next();
590 lastValue = objectStack.last();
591 objectStack.removeLast();
592 break;
593 }
594 startParseObject:
595 case StartParseObject: {
596 JSObject* object = constructEmptyObject(m_exec);
597 objectStack.append(object);
598
599 TokenType type = m_lexer.next();
14957cd0 600 if (type == TokString || (m_mode != StrictJSON && type == TokIdentifier)) {
6fe7ccc8 601 LiteralParserToken<CharType> identifierToken = m_lexer.currentToken();
ba379fdc
A
602
603 // Check for colon
6fe7ccc8 604 if (m_lexer.next() != TokColon) {
93a37866 605 m_parseErrorMessage = ASCIILiteral("Expected ':' before value in object property definition");
ba379fdc 606 return JSValue();
6fe7ccc8 607 }
ba379fdc
A
608
609 m_lexer.next();
6fe7ccc8
A
610 if (identifierToken.stringIs8Bit)
611 identifierStack.append(makeIdentifier(identifierToken.stringToken8, identifierToken.stringLength));
612 else
613 identifierStack.append(makeIdentifier(identifierToken.stringToken16, identifierToken.stringLength));
ba379fdc
A
614 stateStack.append(DoParseObjectEndExpression);
615 goto startParseExpression;
14957cd0 616 }
6fe7ccc8 617 if (type != TokRBrace) {
93a37866 618 m_parseErrorMessage = ASCIILiteral("Expected '}'");
ba379fdc 619 return JSValue();
6fe7ccc8 620 }
ba379fdc
A
621 m_lexer.next();
622 lastValue = objectStack.last();
623 objectStack.removeLast();
624 break;
625 }
626 doParseObjectStartExpression:
627 case DoParseObjectStartExpression: {
628 TokenType type = m_lexer.next();
6fe7ccc8 629 if (type != TokString && (m_mode == StrictJSON || type != TokIdentifier)) {
93a37866 630 m_parseErrorMessage = ASCIILiteral("Property name must be a string literal");
ba379fdc 631 return JSValue();
6fe7ccc8
A
632 }
633 LiteralParserToken<CharType> identifierToken = m_lexer.currentToken();
ba379fdc
A
634
635 // Check for colon
6fe7ccc8 636 if (m_lexer.next() != TokColon) {
93a37866 637 m_parseErrorMessage = ASCIILiteral("Expected ':'");
ba379fdc 638 return JSValue();
6fe7ccc8 639 }
ba379fdc
A
640
641 m_lexer.next();
6fe7ccc8
A
642 if (identifierToken.stringIs8Bit)
643 identifierStack.append(makeIdentifier(identifierToken.stringToken8, identifierToken.stringLength));
644 else
645 identifierStack.append(makeIdentifier(identifierToken.stringToken16, identifierToken.stringLength));
ba379fdc
A
646 stateStack.append(DoParseObjectEndExpression);
647 goto startParseExpression;
648 }
649 case DoParseObjectEndExpression:
650 {
93a37866
A
651 JSObject* object = asObject(objectStack.last());
652 PropertyName ident = identifierStack.last();
ed1e77d3
A
653 if (m_mode != StrictJSON && ident == m_exec->vm().propertyNames->underscoreProto) {
654 if (!visitedUnderscoreProto.add(object).isNewEntry) {
655 m_parseErrorMessage = ASCIILiteral("Attempted to redefine __proto__ property");
656 return JSValue();
657 }
658 CodeBlock* codeBlock = m_exec->codeBlock();
659 PutPropertySlot slot(object, codeBlock ? codeBlock->isStrictMode() : false);
660 objectStack.last().put(m_exec, ident, lastValue, slot);
661 } else {
662 if (Optional<uint32_t> index = parseIndex(ident))
663 object->putDirectIndex(m_exec, index.value(), lastValue);
664 else
665 object->putDirect(m_exec->vm(), ident, lastValue);
666 }
ba379fdc
A
667 identifierStack.removeLast();
668 if (m_lexer.currentToken().type == TokComma)
669 goto doParseObjectStartExpression;
6fe7ccc8 670 if (m_lexer.currentToken().type != TokRBrace) {
93a37866 671 m_parseErrorMessage = ASCIILiteral("Expected '}'");
ba379fdc 672 return JSValue();
6fe7ccc8 673 }
ba379fdc
A
674 m_lexer.next();
675 lastValue = objectStack.last();
676 objectStack.removeLast();
677 break;
678 }
679 startParseExpression:
680 case StartParseExpression: {
681 switch (m_lexer.currentToken().type) {
682 case TokLBracket:
683 goto startParseArray;
684 case TokLBrace:
685 goto startParseObject;
686 case TokString: {
6fe7ccc8 687 LiteralParserToken<CharType> stringToken = m_lexer.currentToken();
ba379fdc 688 m_lexer.next();
6fe7ccc8 689 if (stringToken.stringIs8Bit)
93a37866 690 lastValue = jsString(m_exec, makeIdentifier(stringToken.stringToken8, stringToken.stringLength).string());
6fe7ccc8 691 else
93a37866 692 lastValue = jsString(m_exec, makeIdentifier(stringToken.stringToken16, stringToken.stringLength).string());
ba379fdc
A
693 break;
694 }
695 case TokNumber: {
6fe7ccc8 696 LiteralParserToken<CharType> numberToken = m_lexer.currentToken();
ba379fdc 697 m_lexer.next();
14957cd0 698 lastValue = jsNumber(numberToken.numberToken);
ba379fdc
A
699 break;
700 }
701 case TokNull:
702 m_lexer.next();
703 lastValue = jsNull();
704 break;
705
706 case TokTrue:
707 m_lexer.next();
708 lastValue = jsBoolean(true);
709 break;
710
711 case TokFalse:
712 m_lexer.next();
713 lastValue = jsBoolean(false);
714 break;
6fe7ccc8 715 case TokRBracket:
93a37866 716 m_parseErrorMessage = ASCIILiteral("Unexpected token ']'");
6fe7ccc8
A
717 return JSValue();
718 case TokRBrace:
93a37866 719 m_parseErrorMessage = ASCIILiteral("Unexpected token '}'");
6fe7ccc8
A
720 return JSValue();
721 case TokIdentifier: {
722 const LiteralParserToken<CharType>& token = m_lexer.currentToken();
723 if (token.stringIs8Bit)
ed1e77d3 724 m_parseErrorMessage = String::format("Unexpected identifier \"%s\"", String(m_lexer.currentToken().stringToken8, m_lexer.currentToken().stringLength).ascii().data());
6fe7ccc8 725 else
ed1e77d3 726 m_parseErrorMessage = String::format("Unexpected identifier \"%s\"", String(m_lexer.currentToken().stringToken16, m_lexer.currentToken().stringLength).ascii().data());
6fe7ccc8
A
727 return JSValue();
728 }
729 case TokColon:
93a37866 730 m_parseErrorMessage = ASCIILiteral("Unexpected token ':'");
6fe7ccc8
A
731 return JSValue();
732 case TokLParen:
93a37866 733 m_parseErrorMessage = ASCIILiteral("Unexpected token '('");
6fe7ccc8
A
734 return JSValue();
735 case TokRParen:
93a37866 736 m_parseErrorMessage = ASCIILiteral("Unexpected token ')'");
6fe7ccc8
A
737 return JSValue();
738 case TokComma:
93a37866 739 m_parseErrorMessage = ASCIILiteral("Unexpected token ','");
6fe7ccc8
A
740 return JSValue();
741 case TokDot:
93a37866 742 m_parseErrorMessage = ASCIILiteral("Unexpected token '.'");
6fe7ccc8
A
743 return JSValue();
744 case TokAssign:
93a37866 745 m_parseErrorMessage = ASCIILiteral("Unexpected token '='");
6fe7ccc8
A
746 return JSValue();
747 case TokSemi:
93a37866 748 m_parseErrorMessage = ASCIILiteral("Unexpected token ';'");
6fe7ccc8
A
749 return JSValue();
750 case TokEnd:
93a37866 751 m_parseErrorMessage = ASCIILiteral("Unexpected EOF");
6fe7ccc8
A
752 return JSValue();
753 case TokError:
ba379fdc
A
754 default:
755 // Error
93a37866 756 m_parseErrorMessage = ASCIILiteral("Could not parse value expression");
ba379fdc
A
757 return JSValue();
758 }
759 break;
760 }
761 case StartParseStatement: {
762 switch (m_lexer.currentToken().type) {
763 case TokLBracket:
764 case TokNumber:
765 case TokString:
766 goto startParseExpression;
767
768 case TokLParen: {
769 m_lexer.next();
770 stateStack.append(StartParseStatementEndStatement);
771 goto startParseExpression;
772 }
6fe7ccc8 773 case TokRBracket:
93a37866 774 m_parseErrorMessage = ASCIILiteral("Unexpected token ']'");
6fe7ccc8
A
775 return JSValue();
776 case TokLBrace:
93a37866 777 m_parseErrorMessage = ASCIILiteral("Unexpected token '{'");
6fe7ccc8
A
778 return JSValue();
779 case TokRBrace:
93a37866 780 m_parseErrorMessage = ASCIILiteral("Unexpected token '}'");
6fe7ccc8
A
781 return JSValue();
782 case TokIdentifier:
93a37866 783 m_parseErrorMessage = ASCIILiteral("Unexpected identifier");
6fe7ccc8
A
784 return JSValue();
785 case TokColon:
93a37866 786 m_parseErrorMessage = ASCIILiteral("Unexpected token ':'");
6fe7ccc8
A
787 return JSValue();
788 case TokRParen:
93a37866 789 m_parseErrorMessage = ASCIILiteral("Unexpected token ')'");
6fe7ccc8
A
790 return JSValue();
791 case TokComma:
93a37866 792 m_parseErrorMessage = ASCIILiteral("Unexpected token ','");
6fe7ccc8
A
793 return JSValue();
794 case TokTrue:
93a37866 795 m_parseErrorMessage = ASCIILiteral("Unexpected token 'true'");
6fe7ccc8
A
796 return JSValue();
797 case TokFalse:
93a37866 798 m_parseErrorMessage = ASCIILiteral("Unexpected token 'false'");
6fe7ccc8
A
799 return JSValue();
800 case TokNull:
93a37866 801 m_parseErrorMessage = ASCIILiteral("Unexpected token 'null'");
6fe7ccc8
A
802 return JSValue();
803 case TokEnd:
93a37866 804 m_parseErrorMessage = ASCIILiteral("Unexpected EOF");
6fe7ccc8
A
805 return JSValue();
806 case TokDot:
93a37866 807 m_parseErrorMessage = ASCIILiteral("Unexpected token '.'");
6fe7ccc8
A
808 return JSValue();
809 case TokAssign:
93a37866 810 m_parseErrorMessage = ASCIILiteral("Unexpected token '='");
6fe7ccc8
A
811 return JSValue();
812 case TokSemi:
93a37866 813 m_parseErrorMessage = ASCIILiteral("Unexpected token ';'");
6fe7ccc8
A
814 return JSValue();
815 case TokError:
ba379fdc 816 default:
93a37866 817 m_parseErrorMessage = ASCIILiteral("Could not parse statement");
ba379fdc
A
818 return JSValue();
819 }
820 }
821 case StartParseStatementEndStatement: {
822 ASSERT(stateStack.isEmpty());
823 if (m_lexer.currentToken().type != TokRParen)
824 return JSValue();
825 if (m_lexer.next() == TokEnd)
826 return lastValue;
93a37866 827 m_parseErrorMessage = ASCIILiteral("Unexpected content at end of JSON literal");
ba379fdc
A
828 return JSValue();
829 }
830 default:
93a37866 831 RELEASE_ASSERT_NOT_REACHED();
ba379fdc
A
832 }
833 if (stateStack.isEmpty())
834 return lastValue;
835 state = stateStack.last();
836 stateStack.removeLast();
837 continue;
838 }
839}
840
6fe7ccc8
A
841// Instantiate the two flavors of LiteralParser we need instead of putting most of this file in LiteralParser.h
842template class LiteralParser<LChar>;
843template class LiteralParser<UChar>;
844
ba379fdc 845}