/*
* 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
#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 <wtf/ASCIICType.h>
#include <wtf/dtoa.h>
+#include <wtf/text/StringBuilder.h>
namespace JSC {
-static inline bool isJSONWhiteSpace(const UChar& c)
+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;
}
-bool LiteralParser::tryJSONPParse(Vector<JSONPData>& results, bool needsFullSourceInfo)
+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, 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: {
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: {
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);
return m_lexer.currentToken().type == TokEnd;
}
-ALWAYS_INLINE const Identifier LiteralParser::makeIdentifier(const UChar* characters, size_t length)
+template <typename CharType>
+ALWAYS_INLINE const Identifier LiteralParser<CharType>::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::ParserMode mode> LiteralParser::TokenType LiteralParser::Lexer::lex(LiteralParserToken& token)
+template <typename CharType>
+ALWAYS_INLINE const Identifier LiteralParser<CharType>::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 <typename CharType>
+template <ParserMode mode> TokenType LiteralParser<CharType>::Lexer::lex(LiteralParserToken<CharType>& token)
{
while (m_ptr < m_end && isJSONWhiteSpace(*m_ptr))
++m_ptr;
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<mode, '\''>(token);
}
}
+ m_lexErrorMessage = String::format("Unrecognized token '%c'", *m_ptr).impl();
return TokError;
}
-LiteralParser::TokenType LiteralParser::Lexer::next()
+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 == 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 <typename CharType>
+TokenType LiteralParser<CharType>::Lexer::next()
{
if (m_mode == NonStrictJSON)
return lex<NonStrictJSON>(m_currentToken);
return lex<StrictJSON>(m_currentToken);
}
-template <LiteralParser::ParserMode mode, UChar terminator> static inline bool isSafeStringCharacter(UChar c)
+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 >= ' ' && (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 <LiteralParser::ParserMode mode, UChar terminator> inline LiteralParser::TokenType LiteralParser::Lexer::lexString(LiteralParserToken& token)
+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 UChar* runStart = m_ptr;
- UStringBuilder builder;
+ const CharType* runStart = m_ptr;
+ StringBuilder builder;
do {
runStart = m_ptr;
- while (m_ptr < m_end && isSafeStringCharacter<mode, terminator>(*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 (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('"');
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<CharType>::convertUnicode(m_ptr[1], m_ptr[2], m_ptr[3], m_ptr[4]));
m_ptr += 5;
break;
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<CharType>(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;
return TokString;
}
-LiteralParser::TokenType LiteralParser::Lexer::lexNumber(LiteralParserToken& token)
+template <typename CharType>
+TokenType LiteralParser<CharType>::Lexer::lexNumber(LiteralParserToken<CharType>& token)
{
// ES5 and json.org define numbers as
// number
// [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))
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;
++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))
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);
+ size_t parsedLength;
+ token.numberToken = parseDouble(token.start, token.end - token.start, parsedLength);
return TokNumber;
}
-JSValue LiteralParser::parse(ParserState initialState)
+template <typename CharType>
+JSValue LiteralParser<CharType>::parse(ParserState initialState)
{
ParserState state = initialState;
MarkedArgumentBuffer objectStack;
JSValue lastValue;
- Vector<ParserState, 16> stateStack;
- Vector<Identifier, 16> identifierStack;
+ Vector<ParserState, 16, UnsafeVectorOverflow> stateStack;
+ Vector<Identifier, 16, UnsafeVectorOverflow> identifierStack;
while (1) {
switch(state) {
startParseArray:
case StartParseArray: {
- JSArray* array = constructEmptyArray(m_exec);
+ JSArray* array = constructEmptyArray(m_exec, 0);
objectStack.append(array);
// fallthrough
}
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();
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();
TokenType type = m_lexer.next();
if (type == TokString || (m_mode != StrictJSON && type == TokIdentifier)) {
- Lexer::LiteralParserToken identifierToken = m_lexer.currentToken();
+ LiteralParserToken<CharType> 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();
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<CharType> 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();
case TokLBrace:
goto startParseObject;
case TokString: {
- Lexer::LiteralParserToken stringToken = m_lexer.currentToken();
+ LiteralParserToken<CharType> 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<CharType> numberToken = m_lexer.currentToken();
m_lexer.next();
lastValue = jsNumber(numberToken.numberToken);
break;
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<CharType>& 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;
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();
}
}
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;
}
}
+// 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>;
+
}