]> git.saurik.com Git - apple/javascriptcore.git/blob - runtime/LiteralParser.cpp
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / runtime / LiteralParser.cpp
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 "JSCInlines.h"
37 #include "StrongInlines.h"
38 #include <wtf/ASCIICType.h>
39 #include <wtf/dtoa.h>
40 #include <wtf/text/StringBuilder.h>
41
42 namespace JSC {
43
44 template <typename CharType>
45 static 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
52 template <typename CharType>
53 bool 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::fromString(&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::fromString(&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::fromString(&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::fromString(&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
132 template <typename CharType>
133 ALWAYS_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::fromString(&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::fromString(&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::fromString(&m_exec->vm(), characters, length);
149 return m_recentIdentifiers[characters[0]];
150 }
151
152 template <typename CharType>
153 ALWAYS_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::fromString(&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::fromString(&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::fromString(&m_exec->vm(), characters, length);
169 return m_recentIdentifiers[characters[0]];
170 }
171
172 template <typename CharType>
173 template <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);
285 return TokError;
286 }
287
288 template <>
289 ALWAYS_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
301 template <>
302 ALWAYS_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
314 template <typename CharType>
315 TokenType 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
324 template <>
325 ALWAYS_INLINE void setParserTokenString<LChar>(LiteralParserToken<LChar>& token, const LChar* string)
326 {
327 token.stringIs8Bit = 1;
328 token.stringToken8 = string;
329 }
330
331 template <>
332 ALWAYS_INLINE void setParserTokenString<UChar>(LiteralParserToken<UChar>& token, const UChar* string)
333 {
334 token.stringIs8Bit = 0;
335 token.stringToken16 = string;
336 }
337
338 template <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
343 template <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
348 template <typename CharType>
349 template <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());
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);
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
454 template <typename CharType>
455 TokenType 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
543 template <typename CharType>
544 JSValue 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 HashSet<JSObject*> visitedUnderscoreProto;
552 while (1) {
553 switch(state) {
554 startParseArray:
555 case StartParseArray: {
556 JSArray* array = constructEmptyArray(m_exec, 0);
557 objectStack.append(array);
558 }
559 doParseArrayStartExpression:
560 FALLTHROUGH;
561 case DoParseArrayStartExpression: {
562 TokenType lastToken = m_lexer.currentToken().type;
563 if (m_lexer.next() == TokRBracket) {
564 if (lastToken == TokComma) {
565 m_parseErrorMessage = ASCIILiteral("Unexpected comma at the end of array expression");
566 return JSValue();
567 }
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: {
578 JSArray* array = asArray(objectStack.last());
579 array->putDirectIndex(m_exec, array->length(), lastValue);
580
581 if (m_lexer.currentToken().type == TokComma)
582 goto doParseArrayStartExpression;
583
584 if (m_lexer.currentToken().type != TokRBracket) {
585 m_parseErrorMessage = ASCIILiteral("Expected ']'");
586 return JSValue();
587 }
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();
600 if (type == TokString || (m_mode != StrictJSON && type == TokIdentifier)) {
601 LiteralParserToken<CharType> identifierToken = m_lexer.currentToken();
602
603 // Check for colon
604 if (m_lexer.next() != TokColon) {
605 m_parseErrorMessage = ASCIILiteral("Expected ':' before value in object property definition");
606 return JSValue();
607 }
608
609 m_lexer.next();
610 if (identifierToken.stringIs8Bit)
611 identifierStack.append(makeIdentifier(identifierToken.stringToken8, identifierToken.stringLength));
612 else
613 identifierStack.append(makeIdentifier(identifierToken.stringToken16, identifierToken.stringLength));
614 stateStack.append(DoParseObjectEndExpression);
615 goto startParseExpression;
616 }
617 if (type != TokRBrace) {
618 m_parseErrorMessage = ASCIILiteral("Expected '}'");
619 return JSValue();
620 }
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();
629 if (type != TokString && (m_mode == StrictJSON || type != TokIdentifier)) {
630 m_parseErrorMessage = ASCIILiteral("Property name must be a string literal");
631 return JSValue();
632 }
633 LiteralParserToken<CharType> identifierToken = m_lexer.currentToken();
634
635 // Check for colon
636 if (m_lexer.next() != TokColon) {
637 m_parseErrorMessage = ASCIILiteral("Expected ':'");
638 return JSValue();
639 }
640
641 m_lexer.next();
642 if (identifierToken.stringIs8Bit)
643 identifierStack.append(makeIdentifier(identifierToken.stringToken8, identifierToken.stringLength));
644 else
645 identifierStack.append(makeIdentifier(identifierToken.stringToken16, identifierToken.stringLength));
646 stateStack.append(DoParseObjectEndExpression);
647 goto startParseExpression;
648 }
649 case DoParseObjectEndExpression:
650 {
651 JSObject* object = asObject(objectStack.last());
652 PropertyName ident = identifierStack.last();
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 }
667 identifierStack.removeLast();
668 if (m_lexer.currentToken().type == TokComma)
669 goto doParseObjectStartExpression;
670 if (m_lexer.currentToken().type != TokRBrace) {
671 m_parseErrorMessage = ASCIILiteral("Expected '}'");
672 return JSValue();
673 }
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: {
687 LiteralParserToken<CharType> stringToken = m_lexer.currentToken();
688 m_lexer.next();
689 if (stringToken.stringIs8Bit)
690 lastValue = jsString(m_exec, makeIdentifier(stringToken.stringToken8, stringToken.stringLength).string());
691 else
692 lastValue = jsString(m_exec, makeIdentifier(stringToken.stringToken16, stringToken.stringLength).string());
693 break;
694 }
695 case TokNumber: {
696 LiteralParserToken<CharType> numberToken = m_lexer.currentToken();
697 m_lexer.next();
698 lastValue = jsNumber(numberToken.numberToken);
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;
715 case TokRBracket:
716 m_parseErrorMessage = ASCIILiteral("Unexpected token ']'");
717 return JSValue();
718 case TokRBrace:
719 m_parseErrorMessage = ASCIILiteral("Unexpected token '}'");
720 return JSValue();
721 case TokIdentifier: {
722 const LiteralParserToken<CharType>& token = m_lexer.currentToken();
723 if (token.stringIs8Bit)
724 m_parseErrorMessage = String::format("Unexpected identifier \"%s\"", String(m_lexer.currentToken().stringToken8, m_lexer.currentToken().stringLength).ascii().data());
725 else
726 m_parseErrorMessage = String::format("Unexpected identifier \"%s\"", String(m_lexer.currentToken().stringToken16, m_lexer.currentToken().stringLength).ascii().data());
727 return JSValue();
728 }
729 case TokColon:
730 m_parseErrorMessage = ASCIILiteral("Unexpected token ':'");
731 return JSValue();
732 case TokLParen:
733 m_parseErrorMessage = ASCIILiteral("Unexpected token '('");
734 return JSValue();
735 case TokRParen:
736 m_parseErrorMessage = ASCIILiteral("Unexpected token ')'");
737 return JSValue();
738 case TokComma:
739 m_parseErrorMessage = ASCIILiteral("Unexpected token ','");
740 return JSValue();
741 case TokDot:
742 m_parseErrorMessage = ASCIILiteral("Unexpected token '.'");
743 return JSValue();
744 case TokAssign:
745 m_parseErrorMessage = ASCIILiteral("Unexpected token '='");
746 return JSValue();
747 case TokSemi:
748 m_parseErrorMessage = ASCIILiteral("Unexpected token ';'");
749 return JSValue();
750 case TokEnd:
751 m_parseErrorMessage = ASCIILiteral("Unexpected EOF");
752 return JSValue();
753 case TokError:
754 default:
755 // Error
756 m_parseErrorMessage = ASCIILiteral("Could not parse value expression");
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 }
773 case TokRBracket:
774 m_parseErrorMessage = ASCIILiteral("Unexpected token ']'");
775 return JSValue();
776 case TokLBrace:
777 m_parseErrorMessage = ASCIILiteral("Unexpected token '{'");
778 return JSValue();
779 case TokRBrace:
780 m_parseErrorMessage = ASCIILiteral("Unexpected token '}'");
781 return JSValue();
782 case TokIdentifier:
783 m_parseErrorMessage = ASCIILiteral("Unexpected identifier");
784 return JSValue();
785 case TokColon:
786 m_parseErrorMessage = ASCIILiteral("Unexpected token ':'");
787 return JSValue();
788 case TokRParen:
789 m_parseErrorMessage = ASCIILiteral("Unexpected token ')'");
790 return JSValue();
791 case TokComma:
792 m_parseErrorMessage = ASCIILiteral("Unexpected token ','");
793 return JSValue();
794 case TokTrue:
795 m_parseErrorMessage = ASCIILiteral("Unexpected token 'true'");
796 return JSValue();
797 case TokFalse:
798 m_parseErrorMessage = ASCIILiteral("Unexpected token 'false'");
799 return JSValue();
800 case TokNull:
801 m_parseErrorMessage = ASCIILiteral("Unexpected token 'null'");
802 return JSValue();
803 case TokEnd:
804 m_parseErrorMessage = ASCIILiteral("Unexpected EOF");
805 return JSValue();
806 case TokDot:
807 m_parseErrorMessage = ASCIILiteral("Unexpected token '.'");
808 return JSValue();
809 case TokAssign:
810 m_parseErrorMessage = ASCIILiteral("Unexpected token '='");
811 return JSValue();
812 case TokSemi:
813 m_parseErrorMessage = ASCIILiteral("Unexpected token ';'");
814 return JSValue();
815 case TokError:
816 default:
817 m_parseErrorMessage = ASCIILiteral("Could not parse statement");
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;
827 m_parseErrorMessage = ASCIILiteral("Unexpected content at end of JSON literal");
828 return JSValue();
829 }
830 default:
831 RELEASE_ASSERT_NOT_REACHED();
832 }
833 if (stateStack.isEmpty())
834 return lastValue;
835 state = stateStack.last();
836 stateStack.removeLast();
837 continue;
838 }
839 }
840
841 // Instantiate the two flavors of LiteralParser we need instead of putting most of this file in LiteralParser.h
842 template class LiteralParser<LChar>;
843 template class LiteralParser<UChar>;
844
845 }