diff options
author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-01-06 14:44:00 +0100 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-01-06 14:44:00 +0100 |
commit | 40736c5763bf61337c8c14e16d8587db021a87d4 (patch) | |
tree | b17a9c00042ad89cb1308e2484491799aa14e9f8 /Source/JavaScriptCore/runtime/LiteralParser.cpp | |
download | qtwebkit-40736c5763bf61337c8c14e16d8587db021a87d4.tar.gz |
Imported WebKit commit 2ea9d364d0f6efa8fa64acf19f451504c59be0e4 (http://svn.webkit.org/repository/webkit/trunk@104285)
Diffstat (limited to 'Source/JavaScriptCore/runtime/LiteralParser.cpp')
-rw-r--r-- | Source/JavaScriptCore/runtime/LiteralParser.cpp | 829 |
1 files changed, 829 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/runtime/LiteralParser.cpp b/Source/JavaScriptCore/runtime/LiteralParser.cpp new file mode 100644 index 000000000..b22b81503 --- /dev/null +++ b/Source/JavaScriptCore/runtime/LiteralParser.cpp @@ -0,0 +1,829 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "LiteralParser.h" + +#include "JSArray.h" +#include "JSString.h" +#include "Lexer.h" +#include "StrongInlines.h" +#include "UStringBuilder.h" +#include <wtf/ASCIICType.h> +#include <wtf/dtoa.h> + +namespace JSC { + +template <typename CharType> +static inline bool isJSONWhiteSpace(const CharType& c) +{ + // The JSON RFC 4627 defines a list of allowed characters to be considered + // insignificant white space: http://www.ietf.org/rfc/rfc4627.txt (2. JSON Grammar). + return c == ' ' || c == 0x9 || c == 0xA || c == 0xD; +} + +template <typename CharType> +bool LiteralParser<CharType>::tryJSONPParse(Vector<JSONPData>& results, bool needsFullSourceInfo) +{ + if (m_lexer.next() != TokIdentifier) + return false; + do { + Vector<JSONPPathEntry> path; + // Unguarded next to start off the lexer + Identifier name = Identifier(&m_exec->globalData(), m_lexer.currentToken().start, m_lexer.currentToken().end - m_lexer.currentToken().start); + JSONPPathEntry entry; + if (name == m_exec->globalData().propertyNames->varKeyword) { + if (m_lexer.next() != TokIdentifier) + return false; + entry.m_type = JSONPPathEntryTypeDeclare; + entry.m_pathEntryName = Identifier(&m_exec->globalData(), m_lexer.currentToken().start, m_lexer.currentToken().end - m_lexer.currentToken().start); + path.append(entry); + } else { + entry.m_type = JSONPPathEntryTypeDot; + entry.m_pathEntryName = Identifier(&m_exec->globalData(), m_lexer.currentToken().start, m_lexer.currentToken().end - m_lexer.currentToken().start); + path.append(entry); + } + if (m_exec->globalData().keywords->isKeyword(entry.m_pathEntryName)) + return false; + TokenType tokenType = m_lexer.next(); + while (tokenType != TokAssign) { + switch (tokenType) { + case TokLBracket: { + entry.m_type = JSONPPathEntryTypeLookup; + if (m_lexer.next() != TokNumber) + return false; + double doubleIndex = m_lexer.currentToken().numberToken; + int index = (int)doubleIndex; + if (index != doubleIndex || index < 0) + return false; + entry.m_pathIndex = index; + if (m_lexer.next() != TokRBracket) + return false; + break; + } + case TokDot: { + entry.m_type = JSONPPathEntryTypeDot; + if (m_lexer.next() != TokIdentifier) + return false; + entry.m_pathEntryName = Identifier(&m_exec->globalData(), m_lexer.currentToken().start, m_lexer.currentToken().end - m_lexer.currentToken().start); + break; + } + case TokLParen: { + if (path.last().m_type != JSONPPathEntryTypeDot || needsFullSourceInfo) + return false; + path.last().m_type = JSONPPathEntryTypeCall; + entry = path.last(); + goto startJSON; + } + default: + return false; + } + path.append(entry); + tokenType = m_lexer.next(); + } + startJSON: + m_lexer.next(); + results.append(JSONPData()); + results.last().m_value.set(m_exec->globalData(), parse(StartParseExpression)); + if (!results.last().m_value) + return false; + results.last().m_path.swap(path); + if (entry.m_type == JSONPPathEntryTypeCall) { + if (m_lexer.currentToken().type != TokRParen) + return false; + m_lexer.next(); + } + if (m_lexer.currentToken().type != TokSemi) + break; + m_lexer.next(); + } while (m_lexer.currentToken().type == TokIdentifier); + return m_lexer.currentToken().type == TokEnd; +} + +template <typename CharType> +ALWAYS_INLINE const Identifier LiteralParser<CharType>::makeIdentifier(const LChar* characters, size_t length) +{ + if (!length) + return m_exec->globalData().propertyNames->emptyIdentifier; + if (characters[0] >= MaximumCachableCharacter) + return Identifier(&m_exec->globalData(), characters, length); + + if (length == 1) { + if (!m_shortIdentifiers[characters[0]].isNull()) + return m_shortIdentifiers[characters[0]]; + m_shortIdentifiers[characters[0]] = Identifier(&m_exec->globalData(), characters, length); + return m_shortIdentifiers[characters[0]]; + } + if (!m_recentIdentifiers[characters[0]].isNull() && Identifier::equal(m_recentIdentifiers[characters[0]].impl(), characters, length)) + return m_recentIdentifiers[characters[0]]; + m_recentIdentifiers[characters[0]] = Identifier(&m_exec->globalData(), characters, length); + return m_recentIdentifiers[characters[0]]; +} + +template <typename CharType> +ALWAYS_INLINE const Identifier LiteralParser<CharType>::makeIdentifier(const UChar* characters, size_t length) +{ + if (!length) + return m_exec->globalData().propertyNames->emptyIdentifier; + if (characters[0] >= MaximumCachableCharacter) + return Identifier(&m_exec->globalData(), characters, length); + + if (length == 1) { + if (!m_shortIdentifiers[characters[0]].isNull()) + return m_shortIdentifiers[characters[0]]; + m_shortIdentifiers[characters[0]] = Identifier(&m_exec->globalData(), characters, length); + return m_shortIdentifiers[characters[0]]; + } + if (!m_recentIdentifiers[characters[0]].isNull() && Identifier::equal(m_recentIdentifiers[characters[0]].impl(), characters, length)) + return m_recentIdentifiers[characters[0]]; + m_recentIdentifiers[characters[0]] = Identifier(&m_exec->globalData(), characters, length); + return m_recentIdentifiers[characters[0]]; +} + +template <typename CharType> +template <ParserMode mode> TokenType LiteralParser<CharType>::Lexer::lex(LiteralParserToken<CharType>& token) +{ + while (m_ptr < m_end && isJSONWhiteSpace(*m_ptr)) + ++m_ptr; + + ASSERT(m_ptr <= m_end); + if (m_ptr >= m_end) { + token.type = TokEnd; + token.start = token.end = m_ptr; + return TokEnd; + } + token.type = TokError; + token.start = m_ptr; + switch (*m_ptr) { + case '[': + token.type = TokLBracket; + token.end = ++m_ptr; + return TokLBracket; + case ']': + token.type = TokRBracket; + token.end = ++m_ptr; + return TokRBracket; + case '(': + token.type = TokLParen; + token.end = ++m_ptr; + return TokLParen; + case ')': + token.type = TokRParen; + token.end = ++m_ptr; + return TokRParen; + case '{': + token.type = TokLBrace; + token.end = ++m_ptr; + return TokLBrace; + case '}': + token.type = TokRBrace; + token.end = ++m_ptr; + return TokRBrace; + case ',': + token.type = TokComma; + token.end = ++m_ptr; + return TokComma; + case ':': + token.type = TokColon; + token.end = ++m_ptr; + return TokColon; + case '"': + return lexString<mode, '"'>(token); + case 't': + if (m_end - m_ptr >= 4 && m_ptr[1] == 'r' && m_ptr[2] == 'u' && m_ptr[3] == 'e') { + m_ptr += 4; + token.type = TokTrue; + token.end = m_ptr; + return TokTrue; + } + break; + case 'f': + if (m_end - m_ptr >= 5 && m_ptr[1] == 'a' && m_ptr[2] == 'l' && m_ptr[3] == 's' && m_ptr[4] == 'e') { + m_ptr += 5; + token.type = TokFalse; + token.end = m_ptr; + return TokFalse; + } + break; + case 'n': + if (m_end - m_ptr >= 4 && m_ptr[1] == 'u' && m_ptr[2] == 'l' && m_ptr[3] == 'l') { + m_ptr += 4; + token.type = TokNull; + token.end = m_ptr; + return TokNull; + } + break; + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return lexNumber(token); + } + if (m_ptr < m_end) { + if (*m_ptr == '.') { + token.type = TokDot; + token.end = ++m_ptr; + return TokDot; + } + if (*m_ptr == '=') { + token.type = TokAssign; + token.end = ++m_ptr; + return TokAssign; + } + if (*m_ptr == ';') { + token.type = TokSemi; + token.end = ++m_ptr; + return TokAssign; + } + if (isASCIIAlpha(*m_ptr) || *m_ptr == '_' || *m_ptr == '$') + return lexIdentifier(token); + if (*m_ptr == '\'') { + if (mode == StrictJSON) { + m_lexErrorMessage = "Single quotes (\') are not allowed in JSON"; + return TokError; + } + return lexString<mode, '\''>(token); + } + } + m_lexErrorMessage = String::format("Unrecognized token '%c'", *m_ptr).impl(); + return TokError; +} + +template <> +ALWAYS_INLINE TokenType LiteralParser<LChar>::Lexer::lexIdentifier(LiteralParserToken<LChar>& token) +{ + while (m_ptr < m_end && (isASCIIAlphanumeric(*m_ptr) || *m_ptr == '_' || *m_ptr == '$')) + m_ptr++; + token.stringIs8Bit = 1; + token.stringToken8 = token.start; + token.stringLength = m_ptr - token.start; + token.type = TokIdentifier; + token.end = m_ptr; + return TokIdentifier; +} + +template <> +ALWAYS_INLINE TokenType LiteralParser<UChar>::Lexer::lexIdentifier(LiteralParserToken<UChar>& token) +{ + while (m_ptr < m_end && (isASCIIAlphanumeric(*m_ptr) || *m_ptr == '_' || *m_ptr == '$')) + m_ptr++; + token.stringIs8Bit = 0; + token.stringToken16 = token.start; + token.stringLength = m_ptr - token.start; + token.type = TokIdentifier; + token.end = m_ptr; + return TokIdentifier; +} + +template <typename CharType> +TokenType LiteralParser<CharType>::Lexer::next() +{ + if (m_mode == NonStrictJSON) + return lex<NonStrictJSON>(m_currentToken); + if (m_mode == JSONP) + return lex<JSONP>(m_currentToken); + return lex<StrictJSON>(m_currentToken); +} + +template <> +ALWAYS_INLINE void setParserTokenString<LChar>(LiteralParserToken<LChar>& token, const LChar* string) +{ + token.stringIs8Bit = 1; + token.stringToken8 = string; +} + +template <> +ALWAYS_INLINE void setParserTokenString<UChar>(LiteralParserToken<UChar>& token, const UChar* string) +{ + token.stringIs8Bit = 0; + token.stringToken16 = string; +} + +template <ParserMode mode, typename CharType, LChar terminator> static inline bool isSafeStringCharacter(LChar c) +{ + return (c >= ' ' && c != '\\' && c != terminator) || (c == '\t' && mode != StrictJSON); +} + +template <ParserMode mode, typename CharType, UChar terminator> static inline bool isSafeStringCharacter(UChar c) +{ + return (c >= ' ' && (mode == StrictJSON || c <= 0xff) && c != '\\' && c != terminator) || (c == '\t' && mode != StrictJSON); +} + +template <typename CharType> +template <ParserMode mode, char terminator> ALWAYS_INLINE TokenType LiteralParser<CharType>::Lexer::lexString(LiteralParserToken<CharType>& token) +{ + ++m_ptr; + const CharType* runStart = m_ptr; + UStringBuilder builder; + do { + runStart = m_ptr; + while (m_ptr < m_end && isSafeStringCharacter<mode, CharType, terminator>(*m_ptr)) + ++m_ptr; + if (builder.length()) + builder.append(runStart, m_ptr - runStart); + if ((mode != NonStrictJSON) && m_ptr < m_end && *m_ptr == '\\') { + if (builder.isEmpty() && runStart < m_ptr) + builder.append(runStart, m_ptr - runStart); + ++m_ptr; + if (m_ptr >= m_end) { + m_lexErrorMessage = "Unterminated string"; + return TokError; + } + switch (*m_ptr) { + case '"': + builder.append('"'); + m_ptr++; + break; + case '\\': + builder.append('\\'); + m_ptr++; + break; + case '/': + builder.append('/'); + m_ptr++; + break; + case 'b': + builder.append('\b'); + m_ptr++; + break; + case 'f': + builder.append('\f'); + m_ptr++; + break; + case 'n': + builder.append('\n'); + m_ptr++; + break; + case 'r': + builder.append('\r'); + m_ptr++; + break; + case 't': + builder.append('\t'); + m_ptr++; + break; + + case 'u': + if ((m_end - m_ptr) < 5) { + m_lexErrorMessage = "\\u must be followed by 4 hex digits"; + return TokError; + } // uNNNN == 5 characters + for (int i = 1; i < 5; i++) { + if (!isASCIIHexDigit(m_ptr[i])) { + m_lexErrorMessage = String::format("\"\\%s\" is not a valid unicode escape", UString(m_ptr, 5).ascii().data()).impl(); + return TokError; + } + } + builder.append(JSC::Lexer<CharType>::convertUnicode(m_ptr[1], m_ptr[2], m_ptr[3], m_ptr[4])); + m_ptr += 5; + break; + + default: + if (*m_ptr == '\'' && mode != StrictJSON) { + builder.append('\''); + m_ptr++; + break; + } + m_lexErrorMessage = String::format("Invalid escape character %c", *m_ptr).impl(); + return TokError; + } + } + } while ((mode != NonStrictJSON) && m_ptr != runStart && (m_ptr < m_end) && *m_ptr != terminator); + + if (m_ptr >= m_end || *m_ptr != terminator) { + m_lexErrorMessage = "Unterminated string"; + return TokError; + } + + if (builder.isEmpty()) { + token.stringBuffer = UString(); + setParserTokenString<CharType>(token, runStart); + token.stringLength = m_ptr - runStart; + } else { + token.stringBuffer = builder.toUString(); + if (token.stringBuffer.is8Bit()) { + token.stringIs8Bit = 1; + token.stringToken8 = token.stringBuffer.characters8(); + } else { + token.stringIs8Bit = 0; + token.stringToken16 = token.stringBuffer.characters16(); + } + token.stringLength = token.stringBuffer.length(); + } + token.type = TokString; + token.end = ++m_ptr; + return TokString; +} + +template <typename CharType> +TokenType LiteralParser<CharType>::Lexer::lexNumber(LiteralParserToken<CharType>& token) +{ + // ES5 and json.org define numbers as + // number + // int + // int frac? exp? + // + // int + // -? 0 + // -? digit1-9 digits? + // + // digits + // digit digits? + // + // -?(0 | [1-9][0-9]*) ('.' [0-9]+)? ([eE][+-]? [0-9]+)? + + if (m_ptr < m_end && *m_ptr == '-') // -? + ++m_ptr; + + // (0 | [1-9][0-9]*) + if (m_ptr < m_end && *m_ptr == '0') // 0 + ++m_ptr; + else if (m_ptr < m_end && *m_ptr >= '1' && *m_ptr <= '9') { // [1-9] + ++m_ptr; + // [0-9]* + while (m_ptr < m_end && isASCIIDigit(*m_ptr)) + ++m_ptr; + } else { + m_lexErrorMessage = "Invalid number"; + return TokError; + } + + // ('.' [0-9]+)? + if (m_ptr < m_end && *m_ptr == '.') { + ++m_ptr; + // [0-9]+ + if (m_ptr >= m_end || !isASCIIDigit(*m_ptr)) { + m_lexErrorMessage = "Invalid digits after decimal point"; + return TokError; + } + + ++m_ptr; + while (m_ptr < m_end && isASCIIDigit(*m_ptr)) + ++m_ptr; + } else if (m_ptr < m_end && (*m_ptr != 'e' && *m_ptr != 'E') && (m_ptr - token.start) < 10) { + int result = 0; + token.type = TokNumber; + token.end = m_ptr; + const CharType* digit = token.start; + int negative = 1; + if (*digit == '-') { + negative = -1; + digit++; + } + + while (digit < m_ptr) + result = result * 10 + (*digit++) - '0'; + result *= negative; + token.numberToken = result; + return TokNumber; + } + + // ([eE][+-]? [0-9]+)? + if (m_ptr < m_end && (*m_ptr == 'e' || *m_ptr == 'E')) { // [eE] + ++m_ptr; + + // [-+]? + if (m_ptr < m_end && (*m_ptr == '-' || *m_ptr == '+')) + ++m_ptr; + + // [0-9]+ + if (m_ptr >= m_end || !isASCIIDigit(*m_ptr)) { + m_lexErrorMessage = "Exponent symbols should be followed by an optional '+' or '-' and then by at least one number"; + return TokError; + } + + ++m_ptr; + while (m_ptr < m_end && isASCIIDigit(*m_ptr)) + ++m_ptr; + } + + token.type = TokNumber; + token.end = m_ptr; + Vector<char, 64> buffer(token.end - token.start + 1); + int i; + for (i = 0; i < token.end - token.start; i++) { + ASSERT(static_cast<char>(token.start[i]) == token.start[i]); + buffer[i] = static_cast<char>(token.start[i]); + } + buffer[i] = 0; + char* end; + token.numberToken = WTF::strtod(buffer.data(), &end); + ASSERT(buffer.data() + (token.end - token.start) == end); + return TokNumber; +} + +template <typename CharType> +JSValue LiteralParser<CharType>::parse(ParserState initialState) +{ + ParserState state = initialState; + MarkedArgumentBuffer objectStack; + JSValue lastValue; + Vector<ParserState, 16> stateStack; + Vector<Identifier, 16> identifierStack; + while (1) { + switch(state) { + startParseArray: + case StartParseArray: { + JSArray* array = constructEmptyArray(m_exec); + objectStack.append(array); + // fallthrough + } + doParseArrayStartExpression: + case DoParseArrayStartExpression: { + TokenType lastToken = m_lexer.currentToken().type; + if (m_lexer.next() == TokRBracket) { + if (lastToken == TokComma) { + m_parseErrorMessage = "Unexpected comma at the end of array expression"; + return JSValue(); + } + m_lexer.next(); + lastValue = objectStack.last(); + objectStack.removeLast(); + break; + } + + stateStack.append(DoParseArrayEndExpression); + goto startParseExpression; + } + case DoParseArrayEndExpression: { + asArray(objectStack.last())->push(m_exec, lastValue); + + if (m_lexer.currentToken().type == TokComma) + goto doParseArrayStartExpression; + + if (m_lexer.currentToken().type != TokRBracket) { + m_parseErrorMessage = "Expected ']'"; + return JSValue(); + } + + m_lexer.next(); + lastValue = objectStack.last(); + objectStack.removeLast(); + break; + } + startParseObject: + case StartParseObject: { + JSObject* object = constructEmptyObject(m_exec); + objectStack.append(object); + + TokenType type = m_lexer.next(); + if (type == TokString || (m_mode != StrictJSON && type == TokIdentifier)) { + LiteralParserToken<CharType> identifierToken = m_lexer.currentToken(); + + // Check for colon + if (m_lexer.next() != TokColon) { + m_parseErrorMessage = "Expected ':' before value in object property definition"; + return JSValue(); + } + + m_lexer.next(); + if (identifierToken.stringIs8Bit) + identifierStack.append(makeIdentifier(identifierToken.stringToken8, identifierToken.stringLength)); + else + identifierStack.append(makeIdentifier(identifierToken.stringToken16, identifierToken.stringLength)); + stateStack.append(DoParseObjectEndExpression); + goto startParseExpression; + } + if (type != TokRBrace) { + m_parseErrorMessage = "Expected '}'"; + return JSValue(); + } + m_lexer.next(); + lastValue = objectStack.last(); + objectStack.removeLast(); + break; + } + doParseObjectStartExpression: + case DoParseObjectStartExpression: { + TokenType type = m_lexer.next(); + if (type != TokString && (m_mode == StrictJSON || type != TokIdentifier)) { + m_parseErrorMessage = "Property name must be a string literal"; + return JSValue(); + } + LiteralParserToken<CharType> identifierToken = m_lexer.currentToken(); + + // Check for colon + if (m_lexer.next() != TokColon) { + m_parseErrorMessage = "Expected ':'"; + return JSValue(); + } + + m_lexer.next(); + if (identifierToken.stringIs8Bit) + identifierStack.append(makeIdentifier(identifierToken.stringToken8, identifierToken.stringLength)); + else + identifierStack.append(makeIdentifier(identifierToken.stringToken16, identifierToken.stringLength)); + stateStack.append(DoParseObjectEndExpression); + goto startParseExpression; + } + case DoParseObjectEndExpression: + { + asObject(objectStack.last())->putDirect(m_exec->globalData(), identifierStack.last(), lastValue); + identifierStack.removeLast(); + if (m_lexer.currentToken().type == TokComma) + goto doParseObjectStartExpression; + if (m_lexer.currentToken().type != TokRBrace) { + m_parseErrorMessage = "Expected '}'"; + return JSValue(); + } + m_lexer.next(); + lastValue = objectStack.last(); + objectStack.removeLast(); + break; + } + startParseExpression: + case StartParseExpression: { + switch (m_lexer.currentToken().type) { + case TokLBracket: + goto startParseArray; + case TokLBrace: + goto startParseObject; + case TokString: { + LiteralParserToken<CharType> stringToken = m_lexer.currentToken(); + m_lexer.next(); + if (stringToken.stringIs8Bit) + lastValue = jsString(m_exec, makeIdentifier(stringToken.stringToken8, stringToken.stringLength).ustring()); + else + lastValue = jsString(m_exec, makeIdentifier(stringToken.stringToken16, stringToken.stringLength).ustring()); + break; + } + case TokNumber: { + LiteralParserToken<CharType> numberToken = m_lexer.currentToken(); + m_lexer.next(); + lastValue = jsNumber(numberToken.numberToken); + break; + } + case TokNull: + m_lexer.next(); + lastValue = jsNull(); + break; + + case TokTrue: + m_lexer.next(); + lastValue = jsBoolean(true); + break; + + case TokFalse: + m_lexer.next(); + lastValue = jsBoolean(false); + break; + case TokRBracket: + m_parseErrorMessage = "Unexpected token ']'"; + return JSValue(); + case TokRBrace: + m_parseErrorMessage = "Unexpected token '}'"; + return JSValue(); + case TokIdentifier: { + const LiteralParserToken<CharType>& token = m_lexer.currentToken(); + if (token.stringIs8Bit) + m_parseErrorMessage = String::format("Unexpected identifier \"%s\"", UString(m_lexer.currentToken().stringToken8, m_lexer.currentToken().stringLength).ascii().data()).impl(); + else + m_parseErrorMessage = String::format("Unexpected identifier \"%s\"", UString(m_lexer.currentToken().stringToken16, m_lexer.currentToken().stringLength).ascii().data()).impl(); + return JSValue(); + } + case TokColon: + m_parseErrorMessage = "Unexpected token ':'"; + return JSValue(); + case TokLParen: + m_parseErrorMessage = "Unexpected token '('"; + return JSValue(); + case TokRParen: + m_parseErrorMessage = "Unexpected token ')'"; + return JSValue(); + case TokComma: + m_parseErrorMessage = "Unexpected token ','"; + return JSValue(); + case TokDot: + m_parseErrorMessage = "Unexpected token '.'"; + return JSValue(); + case TokAssign: + m_parseErrorMessage = "Unexpected token '='"; + return JSValue(); + case TokSemi: + m_parseErrorMessage = "Unexpected token ';'"; + return JSValue(); + case TokEnd: + m_parseErrorMessage = "Unexpected EOF"; + return JSValue(); + case TokError: + default: + // Error + m_parseErrorMessage = "Could not parse value expression"; + return JSValue(); + } + break; + } + case StartParseStatement: { + switch (m_lexer.currentToken().type) { + case TokLBracket: + case TokNumber: + case TokString: + goto startParseExpression; + + case TokLParen: { + m_lexer.next(); + stateStack.append(StartParseStatementEndStatement); + goto startParseExpression; + } + case TokRBracket: + m_parseErrorMessage = "Unexpected token ']'"; + return JSValue(); + case TokLBrace: + m_parseErrorMessage = "Unexpected token '{'"; + return JSValue(); + case TokRBrace: + m_parseErrorMessage = "Unexpected token '}'"; + return JSValue(); + case TokIdentifier: + m_parseErrorMessage = "Unexpected identifier"; + return JSValue(); + case TokColon: + m_parseErrorMessage = "Unexpected token ':'"; + return JSValue(); + case TokRParen: + m_parseErrorMessage = "Unexpected token ')'"; + return JSValue(); + case TokComma: + m_parseErrorMessage = "Unexpected token ','"; + return JSValue(); + case TokTrue: + m_parseErrorMessage = "Unexpected token 'true'"; + return JSValue(); + case TokFalse: + m_parseErrorMessage = "Unexpected token 'false'"; + return JSValue(); + case TokNull: + m_parseErrorMessage = "Unexpected token 'null'"; + return JSValue(); + case TokEnd: + m_parseErrorMessage = "Unexpected EOF"; + return JSValue(); + case TokDot: + m_parseErrorMessage = "Unexpected token '.'"; + return JSValue(); + case TokAssign: + m_parseErrorMessage = "Unexpected token '='"; + return JSValue(); + case TokSemi: + m_parseErrorMessage = "Unexpected token ';'"; + return JSValue(); + case TokError: + default: + m_parseErrorMessage = "Could not parse statement"; + return JSValue(); + } + } + case StartParseStatementEndStatement: { + ASSERT(stateStack.isEmpty()); + if (m_lexer.currentToken().type != TokRParen) + return JSValue(); + if (m_lexer.next() == TokEnd) + return lastValue; + m_parseErrorMessage = "Unexpected content at end of JSON literal"; + return JSValue(); + } + default: + ASSERT_NOT_REACHED(); + } + if (stateStack.isEmpty()) + return lastValue; + state = stateStack.last(); + stateStack.removeLast(); + continue; + } +} + +// Instantiate the two flavors of LiteralParser we need instead of putting most of this file in LiteralParser.h +template class LiteralParser<LChar>; +template class LiteralParser<UChar>; + +} |