X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/14957cd040308e3eeec43d26bae5d76da13fcd85..4be4e30906bcb8ee30b4d189205cb70bad6707ce:/runtime/LiteralParser.cpp diff --git a/runtime/LiteralParser.cpp b/runtime/LiteralParser.cpp index ed42d0d..f594518 100644 --- a/runtime/LiteralParser.cpp +++ b/runtime/LiteralParser.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2009 Apple Inc. All rights reserved. + * Copyright (C) 2012 Mathias Bynens (mathias@qiwi.be) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,45 +27,54 @@ #include "config.h" #include "LiteralParser.h" +#include "ButterflyInlines.h" +#include "CopiedSpaceInlines.h" #include "JSArray.h" #include "JSString.h" #include "Lexer.h" -#include "UStringBuilder.h" +#include "ObjectConstructor.h" +#include "Operations.h" +#include "StrongInlines.h" #include #include +#include namespace JSC { -static inline bool isJSONWhiteSpace(const UChar& c) +template +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; } -bool LiteralParser::tryJSONPParse(Vector& results, bool needsFullSourceInfo) +template +bool LiteralParser::tryJSONPParse(Vector& results, bool needsFullSourceInfo) { if (m_lexer.next() != TokIdentifier) return false; do { Vector path; // Unguarded next to start off the lexer - Identifier name = Identifier(m_exec, m_lexer.currentToken().start, m_lexer.currentToken().end - m_lexer.currentToken().start); + Identifier name = Identifier(&m_exec->vm(), m_lexer.currentToken().start, m_lexer.currentToken().end - m_lexer.currentToken().start); JSONPPathEntry entry; - if (name == m_exec->globalData().propertyNames->varKeyword) { + if (name == m_exec->vm().propertyNames->varKeyword) { if (m_lexer.next() != TokIdentifier) return false; entry.m_type = JSONPPathEntryTypeDeclare; - entry.m_pathEntryName = Identifier(m_exec, m_lexer.currentToken().start, m_lexer.currentToken().end - m_lexer.currentToken().start); + entry.m_pathEntryName = Identifier(&m_exec->vm(), 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, m_lexer.currentToken().start, m_lexer.currentToken().end - m_lexer.currentToken().start); + entry.m_pathEntryName = Identifier(&m_exec->vm(), m_lexer.currentToken().start, m_lexer.currentToken().end - m_lexer.currentToken().start); path.append(entry); } - if (m_exec->globalData().lexer->isKeyword(entry.m_pathEntryName)) + if (m_exec->vm().keywords->isKeyword(entry.m_pathEntryName)) return false; TokenType tokenType = m_lexer.next(); + if (entry.m_type == JSONPPathEntryTypeDeclare && tokenType != TokAssign) + return false; while (tokenType != TokAssign) { switch (tokenType) { case TokLBracket: { @@ -84,7 +94,7 @@ bool LiteralParser::tryJSONPParse(Vector& results, bool needsFullSour entry.m_type = JSONPPathEntryTypeDot; if (m_lexer.next() != TokIdentifier) return false; - entry.m_pathEntryName = Identifier(m_exec, m_lexer.currentToken().start, m_lexer.currentToken().end - m_lexer.currentToken().start); + entry.m_pathEntryName = Identifier(&m_exec->vm(), m_lexer.currentToken().start, m_lexer.currentToken().end - m_lexer.currentToken().start); break; } case TokLParen: { @@ -103,7 +113,7 @@ bool LiteralParser::tryJSONPParse(Vector& results, bool needsFullSour startJSON: m_lexer.next(); results.append(JSONPData()); - results.last().m_value.set(m_exec->globalData(), parse(StartParseExpression)); + results.last().m_value.set(m_exec->vm(), parse(StartParseExpression)); if (!results.last().m_value) return false; results.last().m_path.swap(path); @@ -119,26 +129,48 @@ bool LiteralParser::tryJSONPParse(Vector& results, bool needsFullSour return m_lexer.currentToken().type == TokEnd; } -ALWAYS_INLINE const Identifier LiteralParser::makeIdentifier(const UChar* characters, size_t length) +template +ALWAYS_INLINE const Identifier LiteralParser::makeIdentifier(const LChar* characters, size_t length) { if (!length) - return m_exec->globalData().propertyNames->emptyIdentifier; + return m_exec->vm().propertyNames->emptyIdentifier; if (characters[0] >= MaximumCachableCharacter) - return Identifier(&m_exec->globalData(), characters, length); + return Identifier(&m_exec->vm(), 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); + m_shortIdentifiers[characters[0]] = Identifier(&m_exec->vm(), 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); + m_recentIdentifiers[characters[0]] = Identifier(&m_exec->vm(), characters, length); return m_recentIdentifiers[characters[0]]; } -template LiteralParser::TokenType LiteralParser::Lexer::lex(LiteralParserToken& token) +template +ALWAYS_INLINE const Identifier LiteralParser::makeIdentifier(const UChar* characters, size_t length) +{ + if (!length) + return m_exec->vm().propertyNames->emptyIdentifier; + if (characters[0] >= MaximumCachableCharacter) + return Identifier(&m_exec->vm(), characters, length); + + if (length == 1) { + if (!m_shortIdentifiers[characters[0]].isNull()) + return m_shortIdentifiers[characters[0]]; + m_shortIdentifiers[characters[0]] = Identifier(&m_exec->vm(), 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->vm(), characters, length); + return m_recentIdentifiers[characters[0]]; +} + +template +template TokenType LiteralParser::Lexer::lex(LiteralParserToken& token) { while (m_ptr < m_end && isJSONWhiteSpace(*m_ptr)) ++m_ptr; @@ -239,25 +271,48 @@ template LiteralParser::TokenType LiteralParser token.end = ++m_ptr; return TokAssign; } - if (isASCIIAlpha(*m_ptr) || *m_ptr == '_' || *m_ptr == '$') { - while (m_ptr < m_end && (isASCIIAlphanumeric(*m_ptr) || *m_ptr == '_' || *m_ptr == '$')) - m_ptr++; - token.stringToken = token.start; - token.stringLength = m_ptr - token.start; - token.type = TokIdentifier; - token.end = m_ptr; - return TokIdentifier; - } + if (isASCIIAlpha(*m_ptr) || *m_ptr == '_' || *m_ptr == '$') + return lexIdentifier(token); if (*m_ptr == '\'') { - if (mode == StrictJSON) + if (mode == StrictJSON) { + m_lexErrorMessage = ASCIILiteral("Single quotes (\') are not allowed in JSON"); return TokError; + } return lexString(token); } } + m_lexErrorMessage = String::format("Unrecognized token '%c'", *m_ptr).impl(); return TokError; } -LiteralParser::TokenType LiteralParser::Lexer::next() +template <> +ALWAYS_INLINE TokenType LiteralParser::Lexer::lexIdentifier(LiteralParserToken& 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::Lexer::lexIdentifier(LiteralParserToken& token) +{ + while (m_ptr < m_end && (isASCIIAlphanumeric(*m_ptr) || *m_ptr == '_' || *m_ptr == '$' || *m_ptr == 0x200C || *m_ptr == 0x200D)) + 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 +TokenType LiteralParser::Lexer::next() { if (m_mode == NonStrictJSON) return lex(m_currentToken); @@ -266,20 +321,39 @@ LiteralParser::TokenType LiteralParser::Lexer::next() return lex(m_currentToken); } -template static inline bool isSafeStringCharacter(UChar c) +template <> +ALWAYS_INLINE void setParserTokenString(LiteralParserToken& token, const LChar* string) +{ + token.stringIs8Bit = 1; + token.stringToken8 = string; +} + +template <> +ALWAYS_INLINE void setParserTokenString(LiteralParserToken& token, const UChar* string) +{ + token.stringIs8Bit = 0; + token.stringToken16 = string; +} + +template static inline bool isSafeStringCharacter(LChar c) { - return (c >= ' ' && (mode == LiteralParser::StrictJSON || c <= 0xff) && c != '\\' && c != terminator) || c == '\t'; + return (c >= ' ' && c != '\\' && c != terminator) || (c == '\t' && mode != StrictJSON); } -// "inline" is required here to help WINSCW compiler resolve specialized argument in templated functions. -template inline LiteralParser::TokenType LiteralParser::Lexer::lexString(LiteralParserToken& token) +template static inline bool isSafeStringCharacter(UChar c) +{ + return (c >= ' ' && (mode == StrictJSON || c <= 0xff) && c != '\\' && c != terminator) || (c == '\t' && mode != StrictJSON); +} + +template +template ALWAYS_INLINE TokenType LiteralParser::Lexer::lexString(LiteralParserToken& token) { ++m_ptr; - const UChar* runStart = m_ptr; - UStringBuilder builder; + const CharType* runStart = m_ptr; + StringBuilder builder; do { runStart = m_ptr; - while (m_ptr < m_end && isSafeStringCharacter(*m_ptr)) + while (m_ptr < m_end && isSafeStringCharacter(*m_ptr)) ++m_ptr; if (builder.length()) builder.append(runStart, m_ptr - runStart); @@ -287,8 +361,10 @@ template inline LiteralParser if (builder.isEmpty() && runStart < m_ptr) builder.append(runStart, m_ptr - runStart); ++m_ptr; - if (m_ptr >= m_end) + if (m_ptr >= m_end) { + m_lexErrorMessage = ASCIILiteral("Unterminated string"); return TokError; + } switch (*m_ptr) { case '"': builder.append('"'); @@ -324,13 +400,17 @@ template inline LiteralParser break; case 'u': - if ((m_end - m_ptr) < 5) // uNNNN == 5 characters + if ((m_end - m_ptr) < 5) { + m_lexErrorMessage = ASCIILiteral("\\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])) + if (!isASCIIHexDigit(m_ptr[i])) { + m_lexErrorMessage = String::format("\"\\%s\" is not a valid unicode escape", String(m_ptr, 5).ascii().data()).impl(); return TokError; + } } - builder.append(JSC::Lexer::convertUnicode(m_ptr[1], m_ptr[2], m_ptr[3], m_ptr[4])); + builder.append(JSC::Lexer::convertUnicode(m_ptr[1], m_ptr[2], m_ptr[3], m_ptr[4])); m_ptr += 5; break; @@ -340,21 +420,30 @@ template inline LiteralParser 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) + if (m_ptr >= m_end || *m_ptr != terminator) { + m_lexErrorMessage = ASCIILiteral("Unterminated string"); return TokError; + } if (builder.isEmpty()) { - token.stringBuffer = UString(); - token.stringToken = runStart; + token.stringBuffer = String(); + setParserTokenString(token, runStart); token.stringLength = m_ptr - runStart; } else { - token.stringBuffer = builder.toUString(); - token.stringToken = token.stringBuffer.characters(); + token.stringBuffer = builder.toString(); + 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; @@ -362,7 +451,8 @@ template inline LiteralParser return TokString; } -LiteralParser::TokenType LiteralParser::Lexer::lexNumber(LiteralParserToken& token) +template +TokenType LiteralParser::Lexer::lexNumber(LiteralParserToken& token) { // ES5 and json.org define numbers as // number @@ -389,15 +479,19 @@ LiteralParser::TokenType LiteralParser::Lexer::lexNumber(LiteralParserToken& tok // [0-9]* while (m_ptr < m_end && isASCIIDigit(*m_ptr)) ++m_ptr; - } else + } else { + m_lexErrorMessage = ASCIILiteral("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)) + if (m_ptr >= m_end || !isASCIIDigit(*m_ptr)) { + m_lexErrorMessage = ASCIILiteral("Invalid digits after decimal point"); return TokError; + } ++m_ptr; while (m_ptr < m_end && isASCIIDigit(*m_ptr)) @@ -406,7 +500,7 @@ LiteralParser::TokenType LiteralParser::Lexer::lexNumber(LiteralParserToken& tok int result = 0; token.type = TokNumber; token.end = m_ptr; - const UChar* digit = token.start; + const CharType* digit = token.start; int negative = 1; if (*digit == '-') { negative = -1; @@ -429,8 +523,10 @@ LiteralParser::TokenType LiteralParser::Lexer::lexNumber(LiteralParserToken& tok ++m_ptr; // [0-9]+ - if (m_ptr >= m_end || !isASCIIDigit(*m_ptr)) + if (m_ptr >= m_end || !isASCIIDigit(*m_ptr)) { + m_lexErrorMessage = ASCIILiteral("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)) @@ -439,31 +535,24 @@ LiteralParser::TokenType LiteralParser::Lexer::lexNumber(LiteralParserToken& tok token.type = TokNumber; token.end = m_ptr; - Vector buffer(token.end - token.start + 1); - int i; - for (i = 0; i < token.end - token.start; i++) { - ASSERT(static_cast(token.start[i]) == token.start[i]); - buffer[i] = static_cast(token.start[i]); - } - buffer[i] = 0; - char* end; - token.numberToken = WTF::strtod(buffer.data(), &end); - ASSERT(buffer.data() + (token.end - token.start) == end); + size_t parsedLength; + token.numberToken = parseDouble(token.start, token.end - token.start, parsedLength); return TokNumber; } -JSValue LiteralParser::parse(ParserState initialState) +template +JSValue LiteralParser::parse(ParserState initialState) { ParserState state = initialState; MarkedArgumentBuffer objectStack; JSValue lastValue; - Vector stateStack; - Vector identifierStack; + Vector stateStack; + Vector identifierStack; while (1) { switch(state) { startParseArray: case StartParseArray: { - JSArray* array = constructEmptyArray(m_exec); + JSArray* array = constructEmptyArray(m_exec, 0); objectStack.append(array); // fallthrough } @@ -471,8 +560,10 @@ JSValue LiteralParser::parse(ParserState initialState) case DoParseArrayStartExpression: { TokenType lastToken = m_lexer.currentToken().type; if (m_lexer.next() == TokRBracket) { - if (lastToken == TokComma) + if (lastToken == TokComma) { + m_parseErrorMessage = ASCIILiteral("Unexpected comma at the end of array expression"); return JSValue(); + } m_lexer.next(); lastValue = objectStack.last(); objectStack.removeLast(); @@ -483,13 +574,16 @@ JSValue LiteralParser::parse(ParserState initialState) goto startParseExpression; } case DoParseArrayEndExpression: { - asArray(objectStack.last())->push(m_exec, lastValue); + JSArray* array = asArray(objectStack.last()); + array->putDirectIndex(m_exec, array->length(), lastValue); if (m_lexer.currentToken().type == TokComma) goto doParseArrayStartExpression; - if (m_lexer.currentToken().type != TokRBracket) + if (m_lexer.currentToken().type != TokRBracket) { + m_parseErrorMessage = ASCIILiteral("Expected ']'"); return JSValue(); + } m_lexer.next(); lastValue = objectStack.last(); @@ -503,19 +597,26 @@ JSValue LiteralParser::parse(ParserState initialState) TokenType type = m_lexer.next(); if (type == TokString || (m_mode != StrictJSON && type == TokIdentifier)) { - Lexer::LiteralParserToken identifierToken = m_lexer.currentToken(); + LiteralParserToken identifierToken = m_lexer.currentToken(); // Check for colon - if (m_lexer.next() != TokColon) + if (m_lexer.next() != TokColon) { + m_parseErrorMessage = ASCIILiteral("Expected ':' before value in object property definition"); return JSValue(); + } m_lexer.next(); - identifierStack.append(makeIdentifier(identifierToken.stringToken, identifierToken.stringLength)); + 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) + if (type != TokRBrace) { + m_parseErrorMessage = ASCIILiteral("Expected '}'"); return JSValue(); + } m_lexer.next(); lastValue = objectStack.last(); objectStack.removeLast(); @@ -524,27 +625,42 @@ JSValue LiteralParser::parse(ParserState initialState) doParseObjectStartExpression: case DoParseObjectStartExpression: { TokenType type = m_lexer.next(); - if (type != TokString && (m_mode == StrictJSON || type != TokIdentifier)) + if (type != TokString && (m_mode == StrictJSON || type != TokIdentifier)) { + m_parseErrorMessage = ASCIILiteral("Property name must be a string literal"); return JSValue(); - Lexer::LiteralParserToken identifierToken = m_lexer.currentToken(); + } + LiteralParserToken identifierToken = m_lexer.currentToken(); // Check for colon - if (m_lexer.next() != TokColon) + if (m_lexer.next() != TokColon) { + m_parseErrorMessage = ASCIILiteral("Expected ':'"); return JSValue(); + } m_lexer.next(); - identifierStack.append(makeIdentifier(identifierToken.stringToken, identifierToken.stringLength)); + 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); + JSObject* object = asObject(objectStack.last()); + PropertyName ident = identifierStack.last(); + unsigned i = ident.asIndex(); + if (i != PropertyName::NotAnIndex) + object->putDirectIndex(m_exec, i, lastValue); + else + object->putDirect(m_exec->vm(), ident, lastValue); identifierStack.removeLast(); if (m_lexer.currentToken().type == TokComma) goto doParseObjectStartExpression; - if (m_lexer.currentToken().type != TokRBrace) + if (m_lexer.currentToken().type != TokRBrace) { + m_parseErrorMessage = ASCIILiteral("Expected '}'"); return JSValue(); + } m_lexer.next(); lastValue = objectStack.last(); objectStack.removeLast(); @@ -558,13 +674,16 @@ JSValue LiteralParser::parse(ParserState initialState) case TokLBrace: goto startParseObject; case TokString: { - Lexer::LiteralParserToken stringToken = m_lexer.currentToken(); + LiteralParserToken stringToken = m_lexer.currentToken(); m_lexer.next(); - lastValue = jsString(m_exec, makeIdentifier(stringToken.stringToken, stringToken.stringLength).ustring()); + if (stringToken.stringIs8Bit) + lastValue = jsString(m_exec, makeIdentifier(stringToken.stringToken8, stringToken.stringLength).string()); + else + lastValue = jsString(m_exec, makeIdentifier(stringToken.stringToken16, stringToken.stringLength).string()); break; } case TokNumber: { - Lexer::LiteralParserToken numberToken = m_lexer.currentToken(); + LiteralParserToken numberToken = m_lexer.currentToken(); m_lexer.next(); lastValue = jsNumber(numberToken.numberToken); break; @@ -583,9 +702,48 @@ JSValue LiteralParser::parse(ParserState initialState) m_lexer.next(); lastValue = jsBoolean(false); break; - + case TokRBracket: + m_parseErrorMessage = ASCIILiteral("Unexpected token ']'"); + return JSValue(); + case TokRBrace: + m_parseErrorMessage = ASCIILiteral("Unexpected token '}'"); + return JSValue(); + case TokIdentifier: { + const LiteralParserToken& token = m_lexer.currentToken(); + if (token.stringIs8Bit) + m_parseErrorMessage = String::format("Unexpected identifier \"%s\"", String(m_lexer.currentToken().stringToken8, m_lexer.currentToken().stringLength).ascii().data()).impl(); + else + m_parseErrorMessage = String::format("Unexpected identifier \"%s\"", String(m_lexer.currentToken().stringToken16, m_lexer.currentToken().stringLength).ascii().data()).impl(); + return JSValue(); + } + case TokColon: + m_parseErrorMessage = ASCIILiteral("Unexpected token ':'"); + return JSValue(); + case TokLParen: + m_parseErrorMessage = ASCIILiteral("Unexpected token '('"); + return JSValue(); + case TokRParen: + m_parseErrorMessage = ASCIILiteral("Unexpected token ')'"); + return JSValue(); + case TokComma: + m_parseErrorMessage = ASCIILiteral("Unexpected token ','"); + return JSValue(); + case TokDot: + m_parseErrorMessage = ASCIILiteral("Unexpected token '.'"); + return JSValue(); + case TokAssign: + m_parseErrorMessage = ASCIILiteral("Unexpected token '='"); + return JSValue(); + case TokSemi: + m_parseErrorMessage = ASCIILiteral("Unexpected token ';'"); + return JSValue(); + case TokEnd: + m_parseErrorMessage = ASCIILiteral("Unexpected EOF"); + return JSValue(); + case TokError: default: // Error + m_parseErrorMessage = ASCIILiteral("Could not parse value expression"); return JSValue(); } break; @@ -602,7 +760,51 @@ JSValue LiteralParser::parse(ParserState initialState) stateStack.append(StartParseStatementEndStatement); goto startParseExpression; } + case TokRBracket: + m_parseErrorMessage = ASCIILiteral("Unexpected token ']'"); + return JSValue(); + case TokLBrace: + m_parseErrorMessage = ASCIILiteral("Unexpected token '{'"); + return JSValue(); + case TokRBrace: + m_parseErrorMessage = ASCIILiteral("Unexpected token '}'"); + return JSValue(); + case TokIdentifier: + m_parseErrorMessage = ASCIILiteral("Unexpected identifier"); + return JSValue(); + case TokColon: + m_parseErrorMessage = ASCIILiteral("Unexpected token ':'"); + return JSValue(); + case TokRParen: + m_parseErrorMessage = ASCIILiteral("Unexpected token ')'"); + return JSValue(); + case TokComma: + m_parseErrorMessage = ASCIILiteral("Unexpected token ','"); + return JSValue(); + case TokTrue: + m_parseErrorMessage = ASCIILiteral("Unexpected token 'true'"); + return JSValue(); + case TokFalse: + m_parseErrorMessage = ASCIILiteral("Unexpected token 'false'"); + return JSValue(); + case TokNull: + m_parseErrorMessage = ASCIILiteral("Unexpected token 'null'"); + return JSValue(); + case TokEnd: + m_parseErrorMessage = ASCIILiteral("Unexpected EOF"); + return JSValue(); + case TokDot: + m_parseErrorMessage = ASCIILiteral("Unexpected token '.'"); + return JSValue(); + case TokAssign: + m_parseErrorMessage = ASCIILiteral("Unexpected token '='"); + return JSValue(); + case TokSemi: + m_parseErrorMessage = ASCIILiteral("Unexpected token ';'"); + return JSValue(); + case TokError: default: + m_parseErrorMessage = ASCIILiteral("Could not parse statement"); return JSValue(); } } @@ -612,10 +814,11 @@ JSValue LiteralParser::parse(ParserState initialState) return JSValue(); if (m_lexer.next() == TokEnd) return lastValue; + m_parseErrorMessage = ASCIILiteral("Unexpected content at end of JSON literal"); return JSValue(); } default: - ASSERT_NOT_REACHED(); + RELEASE_ASSERT_NOT_REACHED(); } if (stateStack.isEmpty()) return lastValue; @@ -625,4 +828,8 @@ JSValue LiteralParser::parse(ParserState initialState) } } +// Instantiate the two flavors of LiteralParser we need instead of putting most of this file in LiteralParser.h +template class LiteralParser; +template class LiteralParser; + }