]> git.saurik.com Git - apple/javascriptcore.git/blame - runtime/LiteralParser.cpp
JavaScriptCore-1218.35.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
A
35#include "ObjectConstructor.h"
36#include "Operations.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
93a37866 60 Identifier name = Identifier(&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;
93a37866 66 entry.m_pathEntryName = Identifier(&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;
93a37866 70 entry.m_pathEntryName = Identifier(&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;
93a37866 97 entry.m_pathEntryName = Identifier(&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)
93a37866 138 return Identifier(&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]];
93a37866 143 m_shortIdentifiers[characters[0]] = Identifier(&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]];
93a37866 148 m_recentIdentifiers[characters[0]] = Identifier(&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)
93a37866 158 return Identifier(&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]];
93a37866 163 m_shortIdentifiers[characters[0]] = Identifier(&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]];
93a37866 168 m_recentIdentifiers[characters[0]] = Identifier(&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 }
6fe7ccc8 284 m_lexErrorMessage = String::format("Unrecognized token '%c'", *m_ptr).impl();
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])) {
93a37866 409 m_lexErrorMessage = String::format("\"\\%s\" is not a valid unicode escape", String(m_ptr, 5).ascii().data()).impl();
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 }
6fe7ccc8 423 m_lexErrorMessage = String::format("Invalid escape character %c", *m_ptr).impl();
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;
ba379fdc
A
551 while (1) {
552 switch(state) {
553 startParseArray:
554 case StartParseArray: {
93a37866 555 JSArray* array = constructEmptyArray(m_exec, 0);
ba379fdc
A
556 objectStack.append(array);
557 // fallthrough
558 }
559 doParseArrayStartExpression:
560 case DoParseArrayStartExpression: {
f9bf01c6 561 TokenType lastToken = m_lexer.currentToken().type;
ba379fdc 562 if (m_lexer.next() == TokRBracket) {
6fe7ccc8 563 if (lastToken == TokComma) {
93a37866 564 m_parseErrorMessage = ASCIILiteral("Unexpected comma at the end of array expression");
f9bf01c6 565 return JSValue();
6fe7ccc8 566 }
ba379fdc
A
567 m_lexer.next();
568 lastValue = objectStack.last();
569 objectStack.removeLast();
570 break;
571 }
572
573 stateStack.append(DoParseArrayEndExpression);
574 goto startParseExpression;
575 }
576 case DoParseArrayEndExpression: {
93a37866
A
577 JSArray* array = asArray(objectStack.last());
578 array->putDirectIndex(m_exec, array->length(), lastValue);
ba379fdc
A
579
580 if (m_lexer.currentToken().type == TokComma)
581 goto doParseArrayStartExpression;
582
6fe7ccc8 583 if (m_lexer.currentToken().type != TokRBracket) {
93a37866 584 m_parseErrorMessage = ASCIILiteral("Expected ']'");
ba379fdc 585 return JSValue();
6fe7ccc8 586 }
ba379fdc
A
587
588 m_lexer.next();
589 lastValue = objectStack.last();
590 objectStack.removeLast();
591 break;
592 }
593 startParseObject:
594 case StartParseObject: {
595 JSObject* object = constructEmptyObject(m_exec);
596 objectStack.append(object);
597
598 TokenType type = m_lexer.next();
14957cd0 599 if (type == TokString || (m_mode != StrictJSON && type == TokIdentifier)) {
6fe7ccc8 600 LiteralParserToken<CharType> identifierToken = m_lexer.currentToken();
ba379fdc
A
601
602 // Check for colon
6fe7ccc8 603 if (m_lexer.next() != TokColon) {
93a37866 604 m_parseErrorMessage = ASCIILiteral("Expected ':' before value in object property definition");
ba379fdc 605 return JSValue();
6fe7ccc8 606 }
ba379fdc
A
607
608 m_lexer.next();
6fe7ccc8
A
609 if (identifierToken.stringIs8Bit)
610 identifierStack.append(makeIdentifier(identifierToken.stringToken8, identifierToken.stringLength));
611 else
612 identifierStack.append(makeIdentifier(identifierToken.stringToken16, identifierToken.stringLength));
ba379fdc
A
613 stateStack.append(DoParseObjectEndExpression);
614 goto startParseExpression;
14957cd0 615 }
6fe7ccc8 616 if (type != TokRBrace) {
93a37866 617 m_parseErrorMessage = ASCIILiteral("Expected '}'");
ba379fdc 618 return JSValue();
6fe7ccc8 619 }
ba379fdc
A
620 m_lexer.next();
621 lastValue = objectStack.last();
622 objectStack.removeLast();
623 break;
624 }
625 doParseObjectStartExpression:
626 case DoParseObjectStartExpression: {
627 TokenType type = m_lexer.next();
6fe7ccc8 628 if (type != TokString && (m_mode == StrictJSON || type != TokIdentifier)) {
93a37866 629 m_parseErrorMessage = ASCIILiteral("Property name must be a string literal");
ba379fdc 630 return JSValue();
6fe7ccc8
A
631 }
632 LiteralParserToken<CharType> identifierToken = m_lexer.currentToken();
ba379fdc
A
633
634 // Check for colon
6fe7ccc8 635 if (m_lexer.next() != TokColon) {
93a37866 636 m_parseErrorMessage = ASCIILiteral("Expected ':'");
ba379fdc 637 return JSValue();
6fe7ccc8 638 }
ba379fdc
A
639
640 m_lexer.next();
6fe7ccc8
A
641 if (identifierToken.stringIs8Bit)
642 identifierStack.append(makeIdentifier(identifierToken.stringToken8, identifierToken.stringLength));
643 else
644 identifierStack.append(makeIdentifier(identifierToken.stringToken16, identifierToken.stringLength));
ba379fdc
A
645 stateStack.append(DoParseObjectEndExpression);
646 goto startParseExpression;
647 }
648 case DoParseObjectEndExpression:
649 {
93a37866
A
650 JSObject* object = asObject(objectStack.last());
651 PropertyName ident = identifierStack.last();
652 unsigned i = ident.asIndex();
653 if (i != PropertyName::NotAnIndex)
654 object->putDirectIndex(m_exec, i, lastValue);
655 else
656 object->putDirect(m_exec->vm(), ident, lastValue);
ba379fdc
A
657 identifierStack.removeLast();
658 if (m_lexer.currentToken().type == TokComma)
659 goto doParseObjectStartExpression;
6fe7ccc8 660 if (m_lexer.currentToken().type != TokRBrace) {
93a37866 661 m_parseErrorMessage = ASCIILiteral("Expected '}'");
ba379fdc 662 return JSValue();
6fe7ccc8 663 }
ba379fdc
A
664 m_lexer.next();
665 lastValue = objectStack.last();
666 objectStack.removeLast();
667 break;
668 }
669 startParseExpression:
670 case StartParseExpression: {
671 switch (m_lexer.currentToken().type) {
672 case TokLBracket:
673 goto startParseArray;
674 case TokLBrace:
675 goto startParseObject;
676 case TokString: {
6fe7ccc8 677 LiteralParserToken<CharType> stringToken = m_lexer.currentToken();
ba379fdc 678 m_lexer.next();
6fe7ccc8 679 if (stringToken.stringIs8Bit)
93a37866 680 lastValue = jsString(m_exec, makeIdentifier(stringToken.stringToken8, stringToken.stringLength).string());
6fe7ccc8 681 else
93a37866 682 lastValue = jsString(m_exec, makeIdentifier(stringToken.stringToken16, stringToken.stringLength).string());
ba379fdc
A
683 break;
684 }
685 case TokNumber: {
6fe7ccc8 686 LiteralParserToken<CharType> numberToken = m_lexer.currentToken();
ba379fdc 687 m_lexer.next();
14957cd0 688 lastValue = jsNumber(numberToken.numberToken);
ba379fdc
A
689 break;
690 }
691 case TokNull:
692 m_lexer.next();
693 lastValue = jsNull();
694 break;
695
696 case TokTrue:
697 m_lexer.next();
698 lastValue = jsBoolean(true);
699 break;
700
701 case TokFalse:
702 m_lexer.next();
703 lastValue = jsBoolean(false);
704 break;
6fe7ccc8 705 case TokRBracket:
93a37866 706 m_parseErrorMessage = ASCIILiteral("Unexpected token ']'");
6fe7ccc8
A
707 return JSValue();
708 case TokRBrace:
93a37866 709 m_parseErrorMessage = ASCIILiteral("Unexpected token '}'");
6fe7ccc8
A
710 return JSValue();
711 case TokIdentifier: {
712 const LiteralParserToken<CharType>& token = m_lexer.currentToken();
713 if (token.stringIs8Bit)
93a37866 714 m_parseErrorMessage = String::format("Unexpected identifier \"%s\"", String(m_lexer.currentToken().stringToken8, m_lexer.currentToken().stringLength).ascii().data()).impl();
6fe7ccc8 715 else
93a37866 716 m_parseErrorMessage = String::format("Unexpected identifier \"%s\"", String(m_lexer.currentToken().stringToken16, m_lexer.currentToken().stringLength).ascii().data()).impl();
6fe7ccc8
A
717 return JSValue();
718 }
719 case TokColon:
93a37866 720 m_parseErrorMessage = ASCIILiteral("Unexpected token ':'");
6fe7ccc8
A
721 return JSValue();
722 case TokLParen:
93a37866 723 m_parseErrorMessage = ASCIILiteral("Unexpected token '('");
6fe7ccc8
A
724 return JSValue();
725 case TokRParen:
93a37866 726 m_parseErrorMessage = ASCIILiteral("Unexpected token ')'");
6fe7ccc8
A
727 return JSValue();
728 case TokComma:
93a37866 729 m_parseErrorMessage = ASCIILiteral("Unexpected token ','");
6fe7ccc8
A
730 return JSValue();
731 case TokDot:
93a37866 732 m_parseErrorMessage = ASCIILiteral("Unexpected token '.'");
6fe7ccc8
A
733 return JSValue();
734 case TokAssign:
93a37866 735 m_parseErrorMessage = ASCIILiteral("Unexpected token '='");
6fe7ccc8
A
736 return JSValue();
737 case TokSemi:
93a37866 738 m_parseErrorMessage = ASCIILiteral("Unexpected token ';'");
6fe7ccc8
A
739 return JSValue();
740 case TokEnd:
93a37866 741 m_parseErrorMessage = ASCIILiteral("Unexpected EOF");
6fe7ccc8
A
742 return JSValue();
743 case TokError:
ba379fdc
A
744 default:
745 // Error
93a37866 746 m_parseErrorMessage = ASCIILiteral("Could not parse value expression");
ba379fdc
A
747 return JSValue();
748 }
749 break;
750 }
751 case StartParseStatement: {
752 switch (m_lexer.currentToken().type) {
753 case TokLBracket:
754 case TokNumber:
755 case TokString:
756 goto startParseExpression;
757
758 case TokLParen: {
759 m_lexer.next();
760 stateStack.append(StartParseStatementEndStatement);
761 goto startParseExpression;
762 }
6fe7ccc8 763 case TokRBracket:
93a37866 764 m_parseErrorMessage = ASCIILiteral("Unexpected token ']'");
6fe7ccc8
A
765 return JSValue();
766 case TokLBrace:
93a37866 767 m_parseErrorMessage = ASCIILiteral("Unexpected token '{'");
6fe7ccc8
A
768 return JSValue();
769 case TokRBrace:
93a37866 770 m_parseErrorMessage = ASCIILiteral("Unexpected token '}'");
6fe7ccc8
A
771 return JSValue();
772 case TokIdentifier:
93a37866 773 m_parseErrorMessage = ASCIILiteral("Unexpected identifier");
6fe7ccc8
A
774 return JSValue();
775 case TokColon:
93a37866 776 m_parseErrorMessage = ASCIILiteral("Unexpected token ':'");
6fe7ccc8
A
777 return JSValue();
778 case TokRParen:
93a37866 779 m_parseErrorMessage = ASCIILiteral("Unexpected token ')'");
6fe7ccc8
A
780 return JSValue();
781 case TokComma:
93a37866 782 m_parseErrorMessage = ASCIILiteral("Unexpected token ','");
6fe7ccc8
A
783 return JSValue();
784 case TokTrue:
93a37866 785 m_parseErrorMessage = ASCIILiteral("Unexpected token 'true'");
6fe7ccc8
A
786 return JSValue();
787 case TokFalse:
93a37866 788 m_parseErrorMessage = ASCIILiteral("Unexpected token 'false'");
6fe7ccc8
A
789 return JSValue();
790 case TokNull:
93a37866 791 m_parseErrorMessage = ASCIILiteral("Unexpected token 'null'");
6fe7ccc8
A
792 return JSValue();
793 case TokEnd:
93a37866 794 m_parseErrorMessage = ASCIILiteral("Unexpected EOF");
6fe7ccc8
A
795 return JSValue();
796 case TokDot:
93a37866 797 m_parseErrorMessage = ASCIILiteral("Unexpected token '.'");
6fe7ccc8
A
798 return JSValue();
799 case TokAssign:
93a37866 800 m_parseErrorMessage = ASCIILiteral("Unexpected token '='");
6fe7ccc8
A
801 return JSValue();
802 case TokSemi:
93a37866 803 m_parseErrorMessage = ASCIILiteral("Unexpected token ';'");
6fe7ccc8
A
804 return JSValue();
805 case TokError:
ba379fdc 806 default:
93a37866 807 m_parseErrorMessage = ASCIILiteral("Could not parse statement");
ba379fdc
A
808 return JSValue();
809 }
810 }
811 case StartParseStatementEndStatement: {
812 ASSERT(stateStack.isEmpty());
813 if (m_lexer.currentToken().type != TokRParen)
814 return JSValue();
815 if (m_lexer.next() == TokEnd)
816 return lastValue;
93a37866 817 m_parseErrorMessage = ASCIILiteral("Unexpected content at end of JSON literal");
ba379fdc
A
818 return JSValue();
819 }
820 default:
93a37866 821 RELEASE_ASSERT_NOT_REACHED();
ba379fdc
A
822 }
823 if (stateStack.isEmpty())
824 return lastValue;
825 state = stateStack.last();
826 stateStack.removeLast();
827 continue;
828 }
829}
830
6fe7ccc8
A
831// Instantiate the two flavors of LiteralParser we need instead of putting most of this file in LiteralParser.h
832template class LiteralParser<LChar>;
833template class LiteralParser<UChar>;
834
ba379fdc 835}