summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/webkit/JavaScriptCore/runtime/LiteralParser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/webkit/JavaScriptCore/runtime/LiteralParser.cpp')
-rw-r--r--src/3rdparty/webkit/JavaScriptCore/runtime/LiteralParser.cpp399
1 files changed, 271 insertions, 128 deletions
diff --git a/src/3rdparty/webkit/JavaScriptCore/runtime/LiteralParser.cpp b/src/3rdparty/webkit/JavaScriptCore/runtime/LiteralParser.cpp
index 10f9a13..3f3fab9 100644
--- a/src/3rdparty/webkit/JavaScriptCore/runtime/LiteralParser.cpp
+++ b/src/3rdparty/webkit/JavaScriptCore/runtime/LiteralParser.cpp
@@ -28,31 +28,12 @@
#include "JSArray.h"
#include "JSString.h"
+#include "Lexer.h"
#include <wtf/ASCIICType.h>
+#include <wtf/dtoa.h>
namespace JSC {
-class LiteralParser::StackGuard {
-public:
- StackGuard(LiteralParser* parser)
- : m_parser(parser)
- {
- m_parser->m_depth++;
- }
- ~StackGuard()
- {
- m_parser->m_depth--;
- }
- bool isSafe() { return m_parser->m_depth < 10; }
-private:
- LiteralParser* m_parser;
-};
-
-static bool isSafeStringCharacter(UChar c)
-{
- return (c >= ' ' && c <= 0xff && c != '\\') || c == '\t';
-}
-
LiteralParser::TokenType LiteralParser::Lexer::lex(LiteralParserToken& token)
{
while (m_ptr < m_end && isASCIISpace(*m_ptr))
@@ -100,8 +81,33 @@ LiteralParser::TokenType LiteralParser::Lexer::lex(LiteralParserToken& token)
token.end = ++m_ptr;
return TokColon;
case '"':
- return lexString(token);
-
+ if (m_mode == StrictJSON)
+ return lexString<StrictJSON>(token);
+ return lexString<NonStrictJSON>(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':
@@ -118,16 +124,80 @@ LiteralParser::TokenType LiteralParser::Lexer::lex(LiteralParserToken& token)
return TokError;
}
-LiteralParser::TokenType LiteralParser::Lexer::lexString(LiteralParserToken& token)
+static inline bool isSafeStringCharacter(UChar c)
+{
+ return (c >= ' ' && c <= 0xff && c != '\\' && c != '"') || c == '\t';
+}
+
+template <LiteralParser::ParserMode mode> LiteralParser::TokenType LiteralParser::Lexer::lexString(LiteralParserToken& token)
{
++m_ptr;
- while (m_ptr < m_end && isSafeStringCharacter(*m_ptr) && *m_ptr != '"')
- ++m_ptr;
- if (m_ptr >= m_end || *m_ptr != '"') {
- token.type = TokError;
- token.end = ++m_ptr;
+ const UChar* runStart;
+ token.stringToken = UString();
+ do {
+ runStart = m_ptr;
+ while (m_ptr < m_end && isSafeStringCharacter(*m_ptr))
+ ++m_ptr;
+ if (runStart < m_ptr)
+ token.stringToken.append(runStart, m_ptr - runStart);
+ if ((mode == StrictJSON) && m_ptr < m_end && *m_ptr == '\\') {
+ ++m_ptr;
+ if (m_ptr >= m_end)
+ return TokError;
+ switch (*m_ptr) {
+ case '"':
+ token.stringToken.append('"');
+ m_ptr++;
+ break;
+ case '\\':
+ token.stringToken.append('\\');
+ m_ptr++;
+ break;
+ case '/':
+ token.stringToken.append('/');
+ m_ptr++;
+ break;
+ case 'b':
+ token.stringToken.append('\b');
+ m_ptr++;
+ break;
+ case 'f':
+ token.stringToken.append('\f');
+ m_ptr++;
+ break;
+ case 'n':
+ token.stringToken.append('\n');
+ m_ptr++;
+ break;
+ case 'r':
+ token.stringToken.append('\r');
+ m_ptr++;
+ break;
+ case 't':
+ token.stringToken.append('\t');
+ m_ptr++;
+ break;
+
+ case 'u':
+ if ((m_end - m_ptr) < 5) // uNNNN == 5 characters
+ return TokError;
+ for (int i = 1; i < 5; i++) {
+ if (!isASCIIHexDigit(m_ptr[i]))
+ return TokError;
+ }
+ token.stringToken.append(JSC::Lexer::convertUnicode(m_ptr[1], m_ptr[2], m_ptr[3], m_ptr[4]));
+ m_ptr += 5;
+ break;
+
+ default:
+ return TokError;
+ }
+ }
+ } while ((mode == StrictJSON) && m_ptr != runStart && (m_ptr < m_end) && *m_ptr != '"');
+
+ if (m_ptr >= m_end || *m_ptr != '"')
return TokError;
- }
+
token.type = TokString;
token.end = ++m_ptr;
return TokString;
@@ -167,7 +237,7 @@ LiteralParser::TokenType LiteralParser::Lexer::lexNumber(LiteralParserToken& tok
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))
return TokError;
++m_ptr;
@@ -184,7 +254,7 @@ 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))
return TokError;
++m_ptr;
@@ -194,113 +264,186 @@ LiteralParser::TokenType LiteralParser::Lexer::lexNumber(LiteralParserToken& tok
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;
}
-JSValue LiteralParser::parseStatement()
+JSValue LiteralParser::parse(ParserState initialState)
{
- StackGuard guard(this);
- if (!guard.isSafe())
- return abortParse();
+ 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: {
+ if (m_lexer.next() == TokRBracket) {
+ m_lexer.next();
+ lastValue = objectStack.last();
+ objectStack.removeLast();
+ break;
+ }
- switch (m_lexer.currentToken().type) {
- case TokLBracket:
- case TokNumber:
- case TokString:
- return parseExpression();
- case TokLParen: {
- m_lexer.next();
- JSValue result = parseExpression();
- if (m_aborted || m_lexer.currentToken().type != TokRParen)
- return abortParse();
- m_lexer.next();
- return result;
- }
- default:
- return abortParse();
- }
-}
+ stateStack.append(DoParseArrayEndExpression);
+ goto startParseExpression;
+ }
+ case DoParseArrayEndExpression: {
+ asArray(objectStack.last())->push(m_exec, lastValue);
+
+ if (m_lexer.currentToken().type == TokComma)
+ goto doParseArrayStartExpression;
-JSValue LiteralParser::parseExpression()
-{
- StackGuard guard(this);
- if (!guard.isSafe())
- return abortParse();
- switch (m_lexer.currentToken().type) {
- case TokLBracket:
- return parseArray();
- case TokLBrace:
- return parseObject();
- case TokString: {
- Lexer::LiteralParserToken stringToken = m_lexer.currentToken();
- m_lexer.next();
- return jsString(m_exec, UString(stringToken.start + 1, stringToken.end - stringToken.start - 2));
- }
- case TokNumber: {
- Lexer::LiteralParserToken numberToken = m_lexer.currentToken();
- m_lexer.next();
- return jsNumber(m_exec, UString(numberToken.start, numberToken.end - numberToken.start).toDouble());
- }
- default:
- return JSValue();
- }
-}
+ if (m_lexer.currentToken().type != TokRBracket)
+ return JSValue();
+
+ m_lexer.next();
+ lastValue = objectStack.last();
+ objectStack.removeLast();
+ break;
+ }
+ startParseObject:
+ case StartParseObject: {
+ JSObject* object = constructEmptyObject(m_exec);
+ objectStack.append(object);
-JSValue LiteralParser::parseArray()
-{
- StackGuard guard(this);
- if (!guard.isSafe())
- return abortParse();
- JSArray* array = constructEmptyArray(m_exec);
- while (true) {
- m_lexer.next();
- JSValue value = parseExpression();
- if (m_aborted)
- return JSValue();
- if (!value)
- break;
- array->push(m_exec, value);
+ TokenType type = m_lexer.next();
+ if (type == TokString) {
+ Lexer::LiteralParserToken identifierToken = m_lexer.currentToken();
- if (m_lexer.currentToken().type != TokComma)
- break;
- }
- if (m_lexer.currentToken().type != TokRBracket)
- return abortParse();
+ // Check for colon
+ if (m_lexer.next() != TokColon)
+ return JSValue();
+
+ m_lexer.next();
+ identifierStack.append(Identifier(m_exec, identifierToken.stringToken));
+ stateStack.append(DoParseObjectEndExpression);
+ goto startParseExpression;
+ } else if (type != TokRBrace)
+ return JSValue();
+ m_lexer.next();
+ lastValue = objectStack.last();
+ objectStack.removeLast();
+ break;
+ }
+ doParseObjectStartExpression:
+ case DoParseObjectStartExpression: {
+ TokenType type = m_lexer.next();
+ if (type != TokString)
+ return JSValue();
+ Lexer::LiteralParserToken identifierToken = m_lexer.currentToken();
- m_lexer.next();
- return array;
-}
+ // Check for colon
+ if (m_lexer.next() != TokColon)
+ return JSValue();
-JSValue LiteralParser::parseObject()
-{
- StackGuard guard(this);
- if (!guard.isSafe())
- return abortParse();
- JSObject* object = constructEmptyObject(m_exec);
-
- while (m_lexer.next() == TokString) {
- Lexer::LiteralParserToken identifierToken = m_lexer.currentToken();
-
- // Check for colon
- if (m_lexer.next() != TokColon)
- return abortParse();
- m_lexer.next();
-
- JSValue value = parseExpression();
- if (!value || m_aborted)
- return abortParse();
-
- Identifier ident(m_exec, identifierToken.start + 1, identifierToken.end - identifierToken.start - 2);
- object->putDirect(ident, value);
-
- if (m_lexer.currentToken().type != TokComma)
- break;
+ m_lexer.next();
+ identifierStack.append(Identifier(m_exec, identifierToken.stringToken));
+ stateStack.append(DoParseObjectEndExpression);
+ goto startParseExpression;
+ }
+ case DoParseObjectEndExpression:
+ {
+ asObject(objectStack.last())->putDirect(identifierStack.last(), lastValue);
+ identifierStack.removeLast();
+ if (m_lexer.currentToken().type == TokComma)
+ goto doParseObjectStartExpression;
+ if (m_lexer.currentToken().type != TokRBrace)
+ 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: {
+ Lexer::LiteralParserToken stringToken = m_lexer.currentToken();
+ m_lexer.next();
+ lastValue = jsString(m_exec, stringToken.stringToken);
+ break;
+ }
+ case TokNumber: {
+ Lexer::LiteralParserToken numberToken = m_lexer.currentToken();
+ m_lexer.next();
+ lastValue = jsNumber(m_exec, 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;
+
+ default:
+ // Error
+ 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;
+ }
+ default:
+ return JSValue();
+ }
+ }
+ case StartParseStatementEndStatement: {
+ ASSERT(stateStack.isEmpty());
+ if (m_lexer.currentToken().type != TokRParen)
+ return JSValue();
+ if (m_lexer.next() == TokEnd)
+ return lastValue;
+ return JSValue();
+ }
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ if (stateStack.isEmpty())
+ return lastValue;
+ state = stateStack.last();
+ stateStack.removeLast();
+ continue;
}
-
- if (m_lexer.currentToken().type != TokRBrace)
- return abortParse();
- m_lexer.next();
- return object;
}
}