Changeset 44923 in webkit
- Timestamp:
- Jun 21, 2009 4:02:13 PM (15 years ago)
- Location:
- trunk
- Files:
-
- 3 added
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JavaScriptCore/ChangeLog
r44922 r44923 1 2009-06-21 Oliver Hunt <oliver@apple.com> 2 3 Reviewed by Darin Adler and Cameron Zwarich. 4 5 Bug 26587: Support JSON.parse 6 <https://bugs.webkit.org/show_bug.cgi?id=26587> 7 8 Extend the LiteralParser to support the full strict JSON 9 grammar, fix a few places where the grammar was incorrectly 10 lenient. Doesn't yet support the JSON.parse reviver function 11 but that does not block the JSON.parse functionality itself. 12 13 * interpreter/Interpreter.cpp: 14 (JSC::Interpreter::callEval): 15 * runtime/JSGlobalObjectFunctions.cpp: 16 (JSC::globalFuncEval): 17 * runtime/JSONObject.cpp: 18 (JSC::JSONProtoFuncParse): 19 * runtime/LiteralParser.cpp: 20 (JSC::LiteralParser::Lexer::lex): 21 (JSC::isSafeStringCharacter): 22 (JSC::LiteralParser::Lexer::lexString): 23 (JSC::LiteralParser::parse): 24 * runtime/LiteralParser.h: 25 (JSC::LiteralParser::LiteralParser): 26 (JSC::LiteralParser::tryJSONParse): 27 (JSC::LiteralParser::): 28 (JSC::LiteralParser::Lexer::Lexer): 29 1 30 2009-06-21 David Levin <levin@chromium.org> 2 31 -
trunk/JavaScriptCore/interpreter/Interpreter.cpp
r44705 r44923 351 351 UString programSource = asString(program)->value(); 352 352 353 LiteralParser preparser(callFrame, programSource );353 LiteralParser preparser(callFrame, programSource, LiteralParser::NonStrictJSON); 354 354 if (JSValue parsedObject = preparser.tryLiteralParse()) 355 355 return parsedObject; -
trunk/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp
r43424 r44923 283 283 UString s = x.toString(exec); 284 284 285 LiteralParser preparser(exec, s );285 LiteralParser preparser(exec, s, LiteralParser::NonStrictJSON); 286 286 if (JSValue parsedObject = preparser.tryLiteralParse()) 287 287 return parsedObject; -
trunk/JavaScriptCore/runtime/JSONObject.cpp
r44813 r44923 30 30 #include "ExceptionHelpers.h" 31 31 #include "JSArray.h" 32 #include "LiteralParser.h" 32 33 #include "PropertyNameArray.h" 33 34 #include <wtf/MathExtras.h> … … 37 38 ASSERT_CLASS_FITS_IN_CELL(JSONObject); 38 39 40 static JSValue JSC_HOST_CALL JSONProtoFuncParse(ExecState*, JSObject*, JSValue, const ArgList&); 39 41 static JSValue JSC_HOST_CALL JSONProtoFuncStringify(ExecState*, JSObject*, JSValue, const ArgList&); 40 42 … … 563 565 /* Source for JSONObject.lut.h 564 566 @begin jsonTable 567 parse JSONProtoFuncParse DontEnum|Function 1 565 568 stringify JSONProtoFuncStringify DontEnum|Function 1 566 569 @end … … 583 586 { 584 587 stringifier->mark(); 588 } 589 590 // ECMA-262 v5 15.12.3 591 JSValue JSC_HOST_CALL JSONProtoFuncParse(ExecState* exec, JSObject*, JSValue, const ArgList& args) 592 { 593 if (args.isEmpty()) 594 return throwError(exec, GeneralError, "JSON.parse requires at least one parameter"); 595 JSValue value = args.at(0); 596 UString source = value.toString(exec); 597 if (exec->hadException()) 598 return jsNull(); 599 600 LiteralParser jsonParser(exec, source, LiteralParser::StrictJSON); 601 JSValue parsedObject = jsonParser.tryLiteralParse(); 602 if (!parsedObject) 603 return throwError(exec, SyntaxError, "Unable to parse JSON string"); 604 605 return parsedObject; 585 606 } 586 607 -
trunk/JavaScriptCore/runtime/LiteralParser.cpp
r44644 r44923 29 29 #include "JSArray.h" 30 30 #include "JSString.h" 31 #include "Lexer.h" 31 32 #include <wtf/ASCIICType.h> 32 33 33 34 namespace JSC { 34 35 static bool isSafeStringCharacter(UChar c)36 {37 return (c >= ' ' && c <= 0xff && c != '\\') || c == '\t';38 }39 35 40 36 LiteralParser::TokenType LiteralParser::Lexer::lex(LiteralParserToken& token) … … 85 81 return TokColon; 86 82 case '"': 87 return lexString(token); 88 83 if (m_mode == StrictJSON) 84 return lexString<StrictJSON>(token); 85 return lexString<NonStrictJSON>(token); 86 case 't': 87 if (m_end - m_ptr >= 4 && m_ptr[1] == 'r' && m_ptr[2] == 'u' && m_ptr[3] == 'e') { 88 m_ptr += 4; 89 token.type = TokTrue; 90 token.end = m_ptr; 91 return TokTrue; 92 } 93 break; 94 case 'f': 95 if (m_end - m_ptr >= 5 && m_ptr[1] == 'a' && m_ptr[2] == 'l' && m_ptr[3] == 's' && m_ptr[4] == 'e') { 96 m_ptr += 5; 97 token.type = TokFalse; 98 token.end = m_ptr; 99 return TokFalse; 100 } 101 break; 102 case 'n': 103 if (m_end - m_ptr >= 4 && m_ptr[1] == 'u' && m_ptr[2] == 'l' && m_ptr[3] == 'l') { 104 m_ptr += 4; 105 token.type = TokNull; 106 token.end = m_ptr; 107 return TokNull; 108 } 109 break; 89 110 case '-': 90 111 case '0': … … 103 124 } 104 125 105 LiteralParser::TokenType LiteralParser::Lexer::lexString(LiteralParserToken& token) 126 static inline bool isSafeStringCharacter(UChar c) 127 { 128 return (c >= ' ' && c <= 0xff && c != '\\' && c != '"') || c == '\t'; 129 } 130 131 template <LiteralParser::ParserMode mode> LiteralParser::TokenType LiteralParser::Lexer::lexString(LiteralParserToken& token) 106 132 { 107 133 ++m_ptr; 108 while (m_ptr < m_end && isSafeStringCharacter(*m_ptr) && *m_ptr != '"') 109 ++m_ptr; 110 if (m_ptr >= m_end || *m_ptr != '"') { 111 token.type = TokError; 112 token.end = ++m_ptr; 134 const UChar* runStart; 135 token.stringToken = UString(); 136 do { 137 runStart = m_ptr; 138 while (m_ptr < m_end && isSafeStringCharacter(*m_ptr)) 139 ++m_ptr; 140 if (runStart < m_ptr) 141 token.stringToken.append(runStart, m_ptr - runStart); 142 if ((mode == StrictJSON) && m_ptr < m_end && *m_ptr == '\\') { 143 ++m_ptr; 144 if (m_ptr >= m_end) 145 return TokError; 146 switch (*m_ptr) { 147 case '"': 148 token.stringToken.append('"'); 149 m_ptr++; 150 break; 151 case '\\': 152 token.stringToken.append('\\'); 153 m_ptr++; 154 break; 155 case '/': 156 token.stringToken.append('/'); 157 m_ptr++; 158 break; 159 case 'b': 160 token.stringToken.append('\b'); 161 m_ptr++; 162 break; 163 case 'f': 164 token.stringToken.append('\f'); 165 m_ptr++; 166 break; 167 case 'n': 168 token.stringToken.append('\n'); 169 m_ptr++; 170 break; 171 case 'r': 172 token.stringToken.append('\r'); 173 m_ptr++; 174 break; 175 case 't': 176 token.stringToken.append('\t'); 177 m_ptr++; 178 break; 179 180 case 'u': 181 if ((m_end - m_ptr) < 5) // uNNNN == 5 characters 182 return TokError; 183 for (int i = 1; i < 5; i++) { 184 if (!isASCIIHexDigit(m_ptr[i])) 185 return TokError; 186 } 187 token.stringToken.append(JSC::Lexer::convertUnicode(m_ptr[1], m_ptr[2], m_ptr[3], m_ptr[4])); 188 m_ptr += 5; 189 break; 190 191 default: 192 return TokError; 193 } 194 } 195 } while ((mode == StrictJSON) && m_ptr != runStart && (m_ptr < m_end) && *m_ptr != '"'); 196 197 if (m_ptr >= m_end || *m_ptr != '"') 113 198 return TokError; 114 } 199 115 200 token.type = TokString; 116 201 token.end = ++m_ptr; … … 152 237 ++m_ptr; 153 238 // [0-9]+ 154 if (m_ptr >= m_end &&!isASCIIDigit(*m_ptr))239 if (m_ptr >= m_end || !isASCIIDigit(*m_ptr)) 155 240 return TokError; 156 241 … … 169 254 170 255 // [0-9]+ 171 if (m_ptr >= m_end &&!isASCIIDigit(*m_ptr))256 if (m_ptr >= m_end || !isASCIIDigit(*m_ptr)) 172 257 return TokError; 173 258 … … 227 312 JSObject* object = constructEmptyObject(m_exec); 228 313 objectStack.append(object); 229 // fallthrough 314 315 TokenType type = m_lexer.next(); 316 if (type == TokString) { 317 Lexer::LiteralParserToken identifierToken = m_lexer.currentToken(); 318 319 // Check for colon 320 if (m_lexer.next() != TokColon) 321 return JSValue(); 322 323 m_lexer.next(); 324 identifierStack.append(Identifier(m_exec, identifierToken.stringToken)); 325 stateStack.append(DoParseObjectEndExpression); 326 goto startParseExpression; 327 } else if (type != TokRBrace) 328 return JSValue(); 329 m_lexer.next(); 330 lastValue = objectStack.last(); 331 objectStack.removeLast(); 332 break; 230 333 } 231 334 doParseObjectStartExpression: … … 240 343 241 344 m_lexer.next(); 242 identifierStack.append(Identifier(m_exec, identifierToken.st art + 1, identifierToken.end - identifierToken.start - 2));345 identifierStack.append(Identifier(m_exec, identifierToken.stringToken)); 243 346 stateStack.append(DoParseObjectEndExpression); 244 347 goto startParseExpression; 245 } else if (type != TokRBrace)348 } else 246 349 return JSValue(); 247 350 m_lexer.next(); … … 273 376 Lexer::LiteralParserToken stringToken = m_lexer.currentToken(); 274 377 m_lexer.next(); 275 lastValue = jsString(m_exec, UString(stringToken.start + 1, stringToken.end - stringToken.start - 2));378 lastValue = jsString(m_exec, stringToken.stringToken); 276 379 break; 277 380 } … … 282 385 break; 283 386 } 387 case TokNull: 388 m_lexer.next(); 389 lastValue = jsNull(); 390 break; 391 392 case TokTrue: 393 m_lexer.next(); 394 lastValue = jsBoolean(true); 395 break; 396 397 case TokFalse: 398 m_lexer.next(); 399 lastValue = jsBoolean(false); 400 break; 401 284 402 default: 285 403 // Error -
trunk/JavaScriptCore/runtime/LiteralParser.h
r44644 r44923 35 35 class LiteralParser { 36 36 public: 37 LiteralParser(ExecState* exec, const UString& s) 37 typedef enum { StrictJSON, NonStrictJSON } ParserMode; 38 LiteralParser(ExecState* exec, const UString& s, ParserMode mode) 38 39 : m_exec(exec) 39 , m_lexer(s) 40 , m_lexer(s, mode) 41 , m_mode(mode) 40 42 { 41 43 } … … 44 46 { 45 47 m_lexer.next(); 46 JSValue result = parse( StartParseStatement);48 JSValue result = parse(m_mode == StrictJSON ? StartParseExpression : StartParseStatement); 47 49 if (m_lexer.currentToken().type != TokEnd) 48 50 return JSValue(); … … 56 58 enum TokenType { TokLBracket, TokRBracket, TokLBrace, TokRBrace, 57 59 TokString, TokIdentifier, TokNumber, TokColon, 58 TokLParen, TokRParen, TokComma, TokEnd, TokError }; 60 TokLParen, TokRParen, TokComma, TokTrue, TokFalse, 61 TokNull, TokEnd, TokError }; 59 62 60 63 class Lexer { … … 64 67 const UChar* start; 65 68 const UChar* end; 69 UString stringToken; 66 70 }; 67 Lexer(const UString& s )71 Lexer(const UString& s, ParserMode mode) 68 72 : m_string(s) 73 , m_mode(mode) 69 74 , m_ptr(s.data()) 70 75 , m_end(s.data() + s.size()) … … 84 89 private: 85 90 TokenType lex(LiteralParserToken&); 86 TokenType lexString(LiteralParserToken&);91 template <ParserMode parserMode> TokenType lexString(LiteralParserToken&); 87 92 TokenType lexNumber(LiteralParserToken&); 88 93 LiteralParserToken m_currentToken; 89 94 UString m_string; 95 ParserMode m_mode; 90 96 const UChar* m_ptr; 91 97 const UChar* m_end; … … 97 103 ExecState* m_exec; 98 104 LiteralParser::Lexer m_lexer; 105 ParserMode m_mode; 99 106 }; 100 107 } -
trunk/LayoutTests/ChangeLog
r44916 r44923 1 2009-06-21 Oliver Hunt <oliver@apple.com> 2 3 Reviewed by Darin Adler and Cameron Zwarich. 4 5 Bug 26587: Support JSON.parse 6 7 Add tests to cover basic usage of JSON.parse 8 9 * fast/js/JSON-parse.html: Added. 10 * fast/js/JSON-parse-expected.txt: Added. 11 * fast/js/resources/JSON-parse.js: Added. 12 (createTests.result): 13 (createTests): 14 1 15 2009-06-21 Drew Wilson <atwilson@google.com> 2 16
Note: See TracChangeset
for help on using the changeset viewer.