]> git.saurik.com Git - apple/javascriptcore.git/blame_incremental - runtime/LiteralParser.cpp
JavaScriptCore-1218.35.tar.gz
[apple/javascriptcore.git] / runtime / LiteralParser.cpp
... / ...
CommitLineData
1/*
2 * Copyright (C) 2009 Apple Inc. All rights reserved.
3 * Copyright (C) 2012 Mathias Bynens (mathias@qiwi.be)
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
30#include "ButterflyInlines.h"
31#include "CopiedSpaceInlines.h"
32#include "JSArray.h"
33#include "JSString.h"
34#include "Lexer.h"
35#include "ObjectConstructor.h"
36#include "Operations.h"
37#include "StrongInlines.h"
38#include <wtf/ASCIICType.h>
39#include <wtf/dtoa.h>
40#include <wtf/text/StringBuilder.h>
41
42namespace JSC {
43
44template <typename CharType>
45static inline bool isJSONWhiteSpace(const CharType& c)
46{
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
52template <typename CharType>
53bool LiteralParser<CharType>::tryJSONPParse(Vector<JSONPData>& results, bool needsFullSourceInfo)
54{
55 if (m_lexer.next() != TokIdentifier)
56 return false;
57 do {
58 Vector<JSONPPathEntry> path;
59 // Unguarded next to start off the lexer
60 Identifier name = Identifier(&m_exec->vm(), m_lexer.currentToken().start, m_lexer.currentToken().end - m_lexer.currentToken().start);
61 JSONPPathEntry entry;
62 if (name == m_exec->vm().propertyNames->varKeyword) {
63 if (m_lexer.next() != TokIdentifier)
64 return false;
65 entry.m_type = JSONPPathEntryTypeDeclare;
66 entry.m_pathEntryName = Identifier(&m_exec->vm(), m_lexer.currentToken().start, m_lexer.currentToken().end - m_lexer.currentToken().start);
67 path.append(entry);
68 } else {
69 entry.m_type = JSONPPathEntryTypeDot;
70 entry.m_pathEntryName = Identifier(&m_exec->vm(), m_lexer.currentToken().start, m_lexer.currentToken().end - m_lexer.currentToken().start);
71 path.append(entry);
72 }
73 if (m_exec->vm().keywords->isKeyword(entry.m_pathEntryName))
74 return false;
75 TokenType tokenType = m_lexer.next();
76 if (entry.m_type == JSONPPathEntryTypeDeclare && tokenType != TokAssign)
77 return false;
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;
97 entry.m_pathEntryName = Identifier(&m_exec->vm(), m_lexer.currentToken().start, m_lexer.currentToken().end - m_lexer.currentToken().start);
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());
116 results.last().m_value.set(m_exec->vm(), parse(StartParseExpression));
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
132template <typename CharType>
133ALWAYS_INLINE const Identifier LiteralParser<CharType>::makeIdentifier(const LChar* characters, size_t length)
134{
135 if (!length)
136 return m_exec->vm().propertyNames->emptyIdentifier;
137 if (characters[0] >= MaximumCachableCharacter)
138 return Identifier(&m_exec->vm(), characters, length);
139
140 if (length == 1) {
141 if (!m_shortIdentifiers[characters[0]].isNull())
142 return m_shortIdentifiers[characters[0]];
143 m_shortIdentifiers[characters[0]] = Identifier(&m_exec->vm(), characters, length);
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]];
148 m_recentIdentifiers[characters[0]] = Identifier(&m_exec->vm(), characters, length);
149 return m_recentIdentifiers[characters[0]];
150}
151
152template <typename CharType>
153ALWAYS_INLINE const Identifier LiteralParser<CharType>::makeIdentifier(const UChar* characters, size_t length)
154{
155 if (!length)
156 return m_exec->vm().propertyNames->emptyIdentifier;
157 if (characters[0] >= MaximumCachableCharacter)
158 return Identifier(&m_exec->vm(), characters, length);
159
160 if (length == 1) {
161 if (!m_shortIdentifiers[characters[0]].isNull())
162 return m_shortIdentifiers[characters[0]];
163 m_shortIdentifiers[characters[0]] = Identifier(&m_exec->vm(), characters, length);
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]];
168 m_recentIdentifiers[characters[0]] = Identifier(&m_exec->vm(), characters, length);
169 return m_recentIdentifiers[characters[0]];
170}
171
172template <typename CharType>
173template <ParserMode mode> TokenType LiteralParser<CharType>::Lexer::lex(LiteralParserToken<CharType>& token)
174{
175 while (m_ptr < m_end && isJSONWhiteSpace(*m_ptr))
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;
198 return TokLParen;
199 case ')':
200 token.type = TokRParen;
201 token.end = ++m_ptr;
202 return TokRParen;
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 '"':
220 return lexString<mode, '"'>(token);
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 }
244 break;
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 }
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 }
274 if (isASCIIAlpha(*m_ptr) || *m_ptr == '_' || *m_ptr == '$')
275 return lexIdentifier(token);
276 if (*m_ptr == '\'') {
277 if (mode == StrictJSON) {
278 m_lexErrorMessage = ASCIILiteral("Single quotes (\') are not allowed in JSON");
279 return TokError;
280 }
281 return lexString<mode, '\''>(token);
282 }
283 }
284 m_lexErrorMessage = String::format("Unrecognized token '%c'", *m_ptr).impl();
285 return TokError;
286}
287
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()
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
324template <>
325ALWAYS_INLINE void setParserTokenString<LChar>(LiteralParserToken<LChar>& token, const LChar* string)
326{
327 token.stringIs8Bit = 1;
328 token.stringToken8 = string;
329}
330
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)
350{
351 ++m_ptr;
352 const CharType* runStart = m_ptr;
353 StringBuilder builder;
354 do {
355 runStart = m_ptr;
356 while (m_ptr < m_end && isSafeStringCharacter<mode, CharType, terminator>(*m_ptr))
357 ++m_ptr;
358 if (builder.length())
359 builder.append(runStart, m_ptr - runStart);
360 if ((mode != NonStrictJSON) && m_ptr < m_end && *m_ptr == '\\') {
361 if (builder.isEmpty() && runStart < m_ptr)
362 builder.append(runStart, m_ptr - runStart);
363 ++m_ptr;
364 if (m_ptr >= m_end) {
365 m_lexErrorMessage = ASCIILiteral("Unterminated string");
366 return TokError;
367 }
368 switch (*m_ptr) {
369 case '"':
370 builder.append('"');
371 m_ptr++;
372 break;
373 case '\\':
374 builder.append('\\');
375 m_ptr++;
376 break;
377 case '/':
378 builder.append('/');
379 m_ptr++;
380 break;
381 case 'b':
382 builder.append('\b');
383 m_ptr++;
384 break;
385 case 'f':
386 builder.append('\f');
387 m_ptr++;
388 break;
389 case 'n':
390 builder.append('\n');
391 m_ptr++;
392 break;
393 case 'r':
394 builder.append('\r');
395 m_ptr++;
396 break;
397 case 't':
398 builder.append('\t');
399 m_ptr++;
400 break;
401
402 case 'u':
403 if ((m_end - m_ptr) < 5) {
404 m_lexErrorMessage = ASCIILiteral("\\u must be followed by 4 hex digits");
405 return TokError;
406 } // uNNNN == 5 characters
407 for (int i = 1; i < 5; i++) {
408 if (!isASCIIHexDigit(m_ptr[i])) {
409 m_lexErrorMessage = String::format("\"\\%s\" is not a valid unicode escape", String(m_ptr, 5).ascii().data()).impl();
410 return TokError;
411 }
412 }
413 builder.append(JSC::Lexer<CharType>::convertUnicode(m_ptr[1], m_ptr[2], m_ptr[3], m_ptr[4]));
414 m_ptr += 5;
415 break;
416
417 default:
418 if (*m_ptr == '\'' && mode != StrictJSON) {
419 builder.append('\'');
420 m_ptr++;
421 break;
422 }
423 m_lexErrorMessage = String::format("Invalid escape character %c", *m_ptr).impl();
424 return TokError;
425 }
426 }
427 } while ((mode != NonStrictJSON) && m_ptr != runStart && (m_ptr < m_end) && *m_ptr != terminator);
428
429 if (m_ptr >= m_end || *m_ptr != terminator) {
430 m_lexErrorMessage = ASCIILiteral("Unterminated string");
431 return TokError;
432 }
433
434 if (builder.isEmpty()) {
435 token.stringBuffer = String();
436 setParserTokenString<CharType>(token, runStart);
437 token.stringLength = m_ptr - runStart;
438 } else {
439 token.stringBuffer = builder.toString();
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 }
447 token.stringLength = token.stringBuffer.length();
448 }
449 token.type = TokString;
450 token.end = ++m_ptr;
451 return TokString;
452}
453
454template <typename CharType>
455TokenType LiteralParser<CharType>::Lexer::lexNumber(LiteralParserToken<CharType>& token)
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;
482 } else {
483 m_lexErrorMessage = ASCIILiteral("Invalid number");
484 return TokError;
485 }
486
487 // ('.' [0-9]+)?
488 if (m_ptr < m_end && *m_ptr == '.') {
489 ++m_ptr;
490 // [0-9]+
491 if (m_ptr >= m_end || !isASCIIDigit(*m_ptr)) {
492 m_lexErrorMessage = ASCIILiteral("Invalid digits after decimal point");
493 return TokError;
494 }
495
496 ++m_ptr;
497 while (m_ptr < m_end && isASCIIDigit(*m_ptr))
498 ++m_ptr;
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;
503 const CharType* digit = token.start;
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;
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]+
526 if (m_ptr >= m_end || !isASCIIDigit(*m_ptr)) {
527 m_lexErrorMessage = ASCIILiteral("Exponent symbols should be followed by an optional '+' or '-' and then by at least one number");
528 return TokError;
529 }
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;
538 size_t parsedLength;
539 token.numberToken = parseDouble(token.start, token.end - token.start, parsedLength);
540 return TokNumber;
541}
542
543template <typename CharType>
544JSValue LiteralParser<CharType>::parse(ParserState initialState)
545{
546 ParserState state = initialState;
547 MarkedArgumentBuffer objectStack;
548 JSValue lastValue;
549 Vector<ParserState, 16, UnsafeVectorOverflow> stateStack;
550 Vector<Identifier, 16, UnsafeVectorOverflow> identifierStack;
551 while (1) {
552 switch(state) {
553 startParseArray:
554 case StartParseArray: {
555 JSArray* array = constructEmptyArray(m_exec, 0);
556 objectStack.append(array);
557 // fallthrough
558 }
559 doParseArrayStartExpression:
560 case DoParseArrayStartExpression: {
561 TokenType lastToken = m_lexer.currentToken().type;
562 if (m_lexer.next() == TokRBracket) {
563 if (lastToken == TokComma) {
564 m_parseErrorMessage = ASCIILiteral("Unexpected comma at the end of array expression");
565 return JSValue();
566 }
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: {
577 JSArray* array = asArray(objectStack.last());
578 array->putDirectIndex(m_exec, array->length(), lastValue);
579
580 if (m_lexer.currentToken().type == TokComma)
581 goto doParseArrayStartExpression;
582
583 if (m_lexer.currentToken().type != TokRBracket) {
584 m_parseErrorMessage = ASCIILiteral("Expected ']'");
585 return JSValue();
586 }
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();
599 if (type == TokString || (m_mode != StrictJSON && type == TokIdentifier)) {
600 LiteralParserToken<CharType> identifierToken = m_lexer.currentToken();
601
602 // Check for colon
603 if (m_lexer.next() != TokColon) {
604 m_parseErrorMessage = ASCIILiteral("Expected ':' before value in object property definition");
605 return JSValue();
606 }
607
608 m_lexer.next();
609 if (identifierToken.stringIs8Bit)
610 identifierStack.append(makeIdentifier(identifierToken.stringToken8, identifierToken.stringLength));
611 else
612 identifierStack.append(makeIdentifier(identifierToken.stringToken16, identifierToken.stringLength));
613 stateStack.append(DoParseObjectEndExpression);
614 goto startParseExpression;
615 }
616 if (type != TokRBrace) {
617 m_parseErrorMessage = ASCIILiteral("Expected '}'");
618 return JSValue();
619 }
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();
628 if (type != TokString && (m_mode == StrictJSON || type != TokIdentifier)) {
629 m_parseErrorMessage = ASCIILiteral("Property name must be a string literal");
630 return JSValue();
631 }
632 LiteralParserToken<CharType> identifierToken = m_lexer.currentToken();
633
634 // Check for colon
635 if (m_lexer.next() != TokColon) {
636 m_parseErrorMessage = ASCIILiteral("Expected ':'");
637 return JSValue();
638 }
639
640 m_lexer.next();
641 if (identifierToken.stringIs8Bit)
642 identifierStack.append(makeIdentifier(identifierToken.stringToken8, identifierToken.stringLength));
643 else
644 identifierStack.append(makeIdentifier(identifierToken.stringToken16, identifierToken.stringLength));
645 stateStack.append(DoParseObjectEndExpression);
646 goto startParseExpression;
647 }
648 case DoParseObjectEndExpression:
649 {
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);
657 identifierStack.removeLast();
658 if (m_lexer.currentToken().type == TokComma)
659 goto doParseObjectStartExpression;
660 if (m_lexer.currentToken().type != TokRBrace) {
661 m_parseErrorMessage = ASCIILiteral("Expected '}'");
662 return JSValue();
663 }
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: {
677 LiteralParserToken<CharType> stringToken = m_lexer.currentToken();
678 m_lexer.next();
679 if (stringToken.stringIs8Bit)
680 lastValue = jsString(m_exec, makeIdentifier(stringToken.stringToken8, stringToken.stringLength).string());
681 else
682 lastValue = jsString(m_exec, makeIdentifier(stringToken.stringToken16, stringToken.stringLength).string());
683 break;
684 }
685 case TokNumber: {
686 LiteralParserToken<CharType> numberToken = m_lexer.currentToken();
687 m_lexer.next();
688 lastValue = jsNumber(numberToken.numberToken);
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;
705 case TokRBracket:
706 m_parseErrorMessage = ASCIILiteral("Unexpected token ']'");
707 return JSValue();
708 case TokRBrace:
709 m_parseErrorMessage = ASCIILiteral("Unexpected token '}'");
710 return JSValue();
711 case TokIdentifier: {
712 const LiteralParserToken<CharType>& token = m_lexer.currentToken();
713 if (token.stringIs8Bit)
714 m_parseErrorMessage = String::format("Unexpected identifier \"%s\"", String(m_lexer.currentToken().stringToken8, m_lexer.currentToken().stringLength).ascii().data()).impl();
715 else
716 m_parseErrorMessage = String::format("Unexpected identifier \"%s\"", String(m_lexer.currentToken().stringToken16, m_lexer.currentToken().stringLength).ascii().data()).impl();
717 return JSValue();
718 }
719 case TokColon:
720 m_parseErrorMessage = ASCIILiteral("Unexpected token ':'");
721 return JSValue();
722 case TokLParen:
723 m_parseErrorMessage = ASCIILiteral("Unexpected token '('");
724 return JSValue();
725 case TokRParen:
726 m_parseErrorMessage = ASCIILiteral("Unexpected token ')'");
727 return JSValue();
728 case TokComma:
729 m_parseErrorMessage = ASCIILiteral("Unexpected token ','");
730 return JSValue();
731 case TokDot:
732 m_parseErrorMessage = ASCIILiteral("Unexpected token '.'");
733 return JSValue();
734 case TokAssign:
735 m_parseErrorMessage = ASCIILiteral("Unexpected token '='");
736 return JSValue();
737 case TokSemi:
738 m_parseErrorMessage = ASCIILiteral("Unexpected token ';'");
739 return JSValue();
740 case TokEnd:
741 m_parseErrorMessage = ASCIILiteral("Unexpected EOF");
742 return JSValue();
743 case TokError:
744 default:
745 // Error
746 m_parseErrorMessage = ASCIILiteral("Could not parse value expression");
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 }
763 case TokRBracket:
764 m_parseErrorMessage = ASCIILiteral("Unexpected token ']'");
765 return JSValue();
766 case TokLBrace:
767 m_parseErrorMessage = ASCIILiteral("Unexpected token '{'");
768 return JSValue();
769 case TokRBrace:
770 m_parseErrorMessage = ASCIILiteral("Unexpected token '}'");
771 return JSValue();
772 case TokIdentifier:
773 m_parseErrorMessage = ASCIILiteral("Unexpected identifier");
774 return JSValue();
775 case TokColon:
776 m_parseErrorMessage = ASCIILiteral("Unexpected token ':'");
777 return JSValue();
778 case TokRParen:
779 m_parseErrorMessage = ASCIILiteral("Unexpected token ')'");
780 return JSValue();
781 case TokComma:
782 m_parseErrorMessage = ASCIILiteral("Unexpected token ','");
783 return JSValue();
784 case TokTrue:
785 m_parseErrorMessage = ASCIILiteral("Unexpected token 'true'");
786 return JSValue();
787 case TokFalse:
788 m_parseErrorMessage = ASCIILiteral("Unexpected token 'false'");
789 return JSValue();
790 case TokNull:
791 m_parseErrorMessage = ASCIILiteral("Unexpected token 'null'");
792 return JSValue();
793 case TokEnd:
794 m_parseErrorMessage = ASCIILiteral("Unexpected EOF");
795 return JSValue();
796 case TokDot:
797 m_parseErrorMessage = ASCIILiteral("Unexpected token '.'");
798 return JSValue();
799 case TokAssign:
800 m_parseErrorMessage = ASCIILiteral("Unexpected token '='");
801 return JSValue();
802 case TokSemi:
803 m_parseErrorMessage = ASCIILiteral("Unexpected token ';'");
804 return JSValue();
805 case TokError:
806 default:
807 m_parseErrorMessage = ASCIILiteral("Could not parse statement");
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;
817 m_parseErrorMessage = ASCIILiteral("Unexpected content at end of JSON literal");
818 return JSValue();
819 }
820 default:
821 RELEASE_ASSERT_NOT_REACHED();
822 }
823 if (stateStack.isEmpty())
824 return lastValue;
825 state = stateStack.last();
826 stateStack.removeLast();
827 continue;
828 }
829}
830
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
835}