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