OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef V8_JSON_PARSER_H_ | 5 #ifndef V8_JSON_PARSER_H_ |
6 #define V8_JSON_PARSER_H_ | 6 #define V8_JSON_PARSER_H_ |
7 | 7 |
8 #include "src/v8.h" | 8 #include "src/v8.h" |
9 | 9 |
10 #include "src/char-predicates-inl.h" | 10 #include "src/char-predicates-inl.h" |
11 #include "src/conversions.h" | 11 #include "src/conversions.h" |
12 #include "src/heap/spaces-inl.h" | 12 #include "src/heap/spaces-inl.h" |
13 #include "src/messages.h" | 13 #include "src/messages.h" |
14 #include "src/token.h" | 14 #include "src/token.h" |
15 | 15 |
16 namespace v8 { | 16 namespace v8 { |
17 namespace internal { | 17 namespace internal { |
18 | 18 |
| 19 enum ParseElementResult { kElementFound, kElementNotFound, kNullHandle }; |
| 20 |
| 21 |
19 // A simple json parser. | 22 // A simple json parser. |
20 template <bool seq_one_byte> | 23 template <bool seq_one_byte> |
21 class JsonParser BASE_EMBEDDED { | 24 class JsonParser BASE_EMBEDDED { |
22 public: | 25 public: |
23 MUST_USE_RESULT static MaybeHandle<Object> Parse(Handle<String> source) { | 26 MUST_USE_RESULT static MaybeHandle<Object> Parse(Handle<String> source) { |
24 return JsonParser(source).ParseJson(); | 27 return JsonParser(source).ParseJson(); |
25 } | 28 } |
26 | 29 |
27 static const int kEndOfString = -1; | 30 static const int kEndOfString = -1; |
28 | 31 |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
148 Handle<Object> ParseJsonValue(); | 151 Handle<Object> ParseJsonValue(); |
149 | 152 |
150 // Parse a JSON object literal (grammar production JSONObject). | 153 // Parse a JSON object literal (grammar production JSONObject). |
151 // An object literal is a squiggly-braced and comma separated sequence | 154 // An object literal is a squiggly-braced and comma separated sequence |
152 // (possibly empty) of key/value pairs, where the key is a JSON string | 155 // (possibly empty) of key/value pairs, where the key is a JSON string |
153 // literal, the value is a JSON value, and the two are separated by a colon. | 156 // literal, the value is a JSON value, and the two are separated by a colon. |
154 // A JSON array doesn't allow numbers and identifiers as keys, like a | 157 // A JSON array doesn't allow numbers and identifiers as keys, like a |
155 // JavaScript array. | 158 // JavaScript array. |
156 Handle<Object> ParseJsonObject(); | 159 Handle<Object> ParseJsonObject(); |
157 | 160 |
| 161 // Helper for ParseJsonObject. Parses the form "123": obj, which is recorded |
| 162 // as an element, not a property. |
| 163 ParseElementResult ParseElement(Handle<JSObject> json_object); |
| 164 |
158 // Parses a JSON array literal (grammar production JSONArray). An array | 165 // Parses a JSON array literal (grammar production JSONArray). An array |
159 // literal is a square-bracketed and comma separated sequence (possibly empty) | 166 // literal is a square-bracketed and comma separated sequence (possibly empty) |
160 // of JSON values. | 167 // of JSON values. |
161 // A JSON array doesn't allow leaving out values from the sequence, nor does | 168 // A JSON array doesn't allow leaving out values from the sequence, nor does |
162 // it allow a terminal comma, like a JavaScript array does. | 169 // it allow a terminal comma, like a JavaScript array does. |
163 Handle<Object> ParseJsonArray(); | 170 Handle<Object> ParseJsonArray(); |
164 | 171 |
165 | 172 |
166 // Mark that a parsing error has happened at the current token, and | 173 // Mark that a parsing error has happened at the current token, and |
167 // return a null handle. Primarily for readability. | 174 // return a null handle. Primarily for readability. |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
292 AdvanceGetChar() == 'l') { | 299 AdvanceGetChar() == 'l') { |
293 AdvanceSkipWhitespace(); | 300 AdvanceSkipWhitespace(); |
294 return factory()->null_value(); | 301 return factory()->null_value(); |
295 } | 302 } |
296 return ReportUnexpectedCharacter(); | 303 return ReportUnexpectedCharacter(); |
297 } | 304 } |
298 return ReportUnexpectedCharacter(); | 305 return ReportUnexpectedCharacter(); |
299 } | 306 } |
300 | 307 |
301 | 308 |
| 309 template <bool seq_one_byte> |
| 310 ParseElementResult JsonParser<seq_one_byte>::ParseElement( |
| 311 Handle<JSObject> json_object) { |
| 312 uint32_t index = 0; |
| 313 // Maybe an array index, try to parse it. |
| 314 if (c0_ == '0') { |
| 315 // With a leading zero, the string has to be "0" only to be an index. |
| 316 Advance(); |
| 317 } else { |
| 318 do { |
| 319 int d = c0_ - '0'; |
| 320 if (index > 429496729U - ((d > 5) ? 1 : 0)) break; |
| 321 index = (index * 10) + d; |
| 322 Advance(); |
| 323 } while (IsDecimalDigit(c0_)); |
| 324 } |
| 325 |
| 326 if (c0_ == '"') { |
| 327 // Successfully parsed index, parse and store element. |
| 328 AdvanceSkipWhitespace(); |
| 329 |
| 330 if (c0_ == ':') { |
| 331 AdvanceSkipWhitespace(); |
| 332 Handle<Object> value = ParseJsonValue(); |
| 333 if (!value.is_null()) { |
| 334 JSObject::SetOwnElement(json_object, index, value, SLOPPY).Assert(); |
| 335 return kElementFound; |
| 336 } else { |
| 337 return kNullHandle; |
| 338 } |
| 339 } |
| 340 } |
| 341 return kElementNotFound; |
| 342 } |
| 343 |
302 // Parse a JSON object. Position must be right at '{'. | 344 // Parse a JSON object. Position must be right at '{'. |
303 template <bool seq_one_byte> | 345 template <bool seq_one_byte> |
304 Handle<Object> JsonParser<seq_one_byte>::ParseJsonObject() { | 346 Handle<Object> JsonParser<seq_one_byte>::ParseJsonObject() { |
305 HandleScope scope(isolate()); | 347 HandleScope scope(isolate()); |
306 Handle<JSObject> json_object = | 348 Handle<JSObject> json_object = |
307 factory()->NewJSObject(object_constructor(), pretenure_); | 349 factory()->NewJSObject(object_constructor(), pretenure_); |
308 Handle<Map> map(json_object->map()); | 350 Handle<Map> map(json_object->map()); |
309 int descriptor = 0; | 351 int descriptor = 0; |
310 ZoneList<Handle<Object> > properties(8, zone()); | 352 ZoneList<Handle<Object> > properties(8, zone()); |
311 DCHECK_EQ(c0_, '{'); | 353 DCHECK_EQ(c0_, '{'); |
312 | 354 |
313 bool transitioning = true; | 355 bool transitioning = true; |
314 | 356 |
315 AdvanceSkipWhitespace(); | 357 AdvanceSkipWhitespace(); |
316 if (c0_ != '}') { | 358 if (c0_ != '}') { |
317 do { | 359 do { |
318 if (c0_ != '"') return ReportUnexpectedCharacter(); | 360 if (c0_ != '"') return ReportUnexpectedCharacter(); |
319 | 361 |
320 int start_position = position_; | 362 int start_position = position_; |
321 Advance(); | 363 Advance(); |
322 | 364 |
323 uint32_t index = 0; | |
324 if (IsDecimalDigit(c0_)) { | 365 if (IsDecimalDigit(c0_)) { |
325 // Maybe an array index, try to parse it. | 366 ParseElementResult element_result = ParseElement(json_object); |
326 if (c0_ == '0') { | 367 if (element_result == kNullHandle) return Handle<Object>::null(); |
327 // With a leading zero, the string has to be "0" only to be an index. | 368 if (element_result == kElementFound) continue; |
328 Advance(); | |
329 } else { | |
330 do { | |
331 int d = c0_ - '0'; | |
332 if (index > 429496729U - ((d > 5) ? 1 : 0)) break; | |
333 index = (index * 10) + d; | |
334 Advance(); | |
335 } while (IsDecimalDigit(c0_)); | |
336 } | |
337 | |
338 if (c0_ == '"') { | |
339 // Successfully parsed index, parse and store element. | |
340 AdvanceSkipWhitespace(); | |
341 | |
342 if (c0_ != ':') return ReportUnexpectedCharacter(); | |
343 AdvanceSkipWhitespace(); | |
344 Handle<Object> value = ParseJsonValue(); | |
345 if (value.is_null()) return ReportUnexpectedCharacter(); | |
346 | |
347 JSObject::SetOwnElement(json_object, index, value, SLOPPY).Assert(); | |
348 continue; | |
349 } | |
350 // Not an index, fallback to the slow path. | |
351 } | 369 } |
| 370 // Not an index, fallback to the slow path. |
352 | 371 |
353 position_ = start_position; | 372 position_ = start_position; |
354 #ifdef DEBUG | 373 #ifdef DEBUG |
355 c0_ = '"'; | 374 c0_ = '"'; |
356 #endif | 375 #endif |
357 | 376 |
358 Handle<String> key; | 377 Handle<String> key; |
359 Handle<Object> value; | 378 Handle<Object> value; |
360 | 379 |
361 // Try to follow existing transitions as long as possible. Once we stop | 380 // Try to follow existing transitions as long as possible. Once we stop |
362 // transitioning, no transition can be found anymore. | 381 // transitioning, no transition can be found anymore. |
| 382 DCHECK(transitioning); |
| 383 // First check whether there is a single expected transition. If so, try |
| 384 // to parse it first. |
| 385 bool follow_expected = false; |
| 386 Handle<Map> target; |
| 387 if (seq_one_byte) { |
| 388 key = TransitionArray::ExpectedTransitionKey(map); |
| 389 follow_expected = !key.is_null() && ParseJsonString(key); |
| 390 } |
| 391 // If the expected transition hits, follow it. |
| 392 if (follow_expected) { |
| 393 target = TransitionArray::ExpectedTransitionTarget(map); |
| 394 } else { |
| 395 // If the expected transition failed, parse an internalized string and |
| 396 // try to find a matching transition. |
| 397 key = ParseJsonInternalizedString(); |
| 398 if (key.is_null()) return ReportUnexpectedCharacter(); |
| 399 |
| 400 target = TransitionArray::FindTransitionToField(map, key); |
| 401 // If a transition was found, follow it and continue. |
| 402 transitioning = !target.is_null(); |
| 403 } |
| 404 if (c0_ != ':') return ReportUnexpectedCharacter(); |
| 405 |
| 406 AdvanceSkipWhitespace(); |
| 407 value = ParseJsonValue(); |
| 408 if (value.is_null()) return ReportUnexpectedCharacter(); |
| 409 |
363 if (transitioning) { | 410 if (transitioning) { |
364 // First check whether there is a single expected transition. If so, try | 411 PropertyDetails details = |
365 // to parse it first. | 412 target->instance_descriptors()->GetDetails(descriptor); |
366 bool follow_expected = false; | 413 Representation expected_representation = details.representation(); |
367 Handle<Map> target; | 414 |
368 if (seq_one_byte) { | 415 if (value->FitsRepresentation(expected_representation)) { |
369 key = TransitionArray::ExpectedTransitionKey(map); | 416 if (expected_representation.IsHeapObject() && |
370 follow_expected = !key.is_null() && ParseJsonString(key); | 417 !target->instance_descriptors() |
| 418 ->GetFieldType(descriptor) |
| 419 ->NowContains(value)) { |
| 420 Handle<HeapType> value_type( |
| 421 value->OptimalType(isolate(), expected_representation)); |
| 422 Map::GeneralizeFieldType(target, descriptor, |
| 423 expected_representation, value_type); |
| 424 } |
| 425 DCHECK(target->instance_descriptors() |
| 426 ->GetFieldType(descriptor) |
| 427 ->NowContains(value)); |
| 428 properties.Add(value, zone()); |
| 429 map = target; |
| 430 descriptor++; |
| 431 continue; |
| 432 } else { |
| 433 transitioning = false; |
371 } | 434 } |
372 // If the expected transition hits, follow it. | 435 } |
373 if (follow_expected) { | |
374 target = TransitionArray::ExpectedTransitionTarget(map); | |
375 } else { | |
376 // If the expected transition failed, parse an internalized string and | |
377 // try to find a matching transition. | |
378 key = ParseJsonInternalizedString(); | |
379 if (key.is_null()) return ReportUnexpectedCharacter(); | |
380 | 436 |
381 target = TransitionArray::FindTransitionToField(map, key); | 437 DCHECK(!transitioning); |
382 // If a transition was found, follow it and continue. | 438 |
383 transitioning = !target.is_null(); | 439 // Commit the intermediate state to the object and stop transitioning. |
| 440 CommitStateToJsonObject(json_object, map, &properties); |
| 441 |
| 442 Runtime::DefineObjectProperty(json_object, key, value, NONE).Check(); |
| 443 } while (transitioning && MatchSkipWhiteSpace(',')); |
| 444 |
| 445 // If we transitioned until the very end, transition the map now. |
| 446 if (transitioning) { |
| 447 CommitStateToJsonObject(json_object, map, &properties); |
| 448 } else { |
| 449 while (MatchSkipWhiteSpace(',')) { |
| 450 HandleScope local_scope(isolate()); |
| 451 if (c0_ != '"') return ReportUnexpectedCharacter(); |
| 452 |
| 453 int start_position = position_; |
| 454 Advance(); |
| 455 |
| 456 if (IsDecimalDigit(c0_)) { |
| 457 ParseElementResult element_result = ParseElement(json_object); |
| 458 if (element_result == kNullHandle) return Handle<Object>::null(); |
| 459 if (element_result == kElementFound) continue; |
384 } | 460 } |
385 if (c0_ != ':') return ReportUnexpectedCharacter(); | 461 // Not an index, fallback to the slow path. |
386 | 462 |
387 AdvanceSkipWhitespace(); | 463 position_ = start_position; |
388 value = ParseJsonValue(); | 464 #ifdef DEBUG |
389 if (value.is_null()) return ReportUnexpectedCharacter(); | 465 c0_ = '"'; |
| 466 #endif |
390 | 467 |
391 if (transitioning) { | 468 Handle<String> key; |
392 PropertyDetails details = | 469 Handle<Object> value; |
393 target->instance_descriptors()->GetDetails(descriptor); | |
394 Representation expected_representation = details.representation(); | |
395 | 470 |
396 if (value->FitsRepresentation(expected_representation)) { | |
397 if (expected_representation.IsHeapObject() && | |
398 !target->instance_descriptors() | |
399 ->GetFieldType(descriptor) | |
400 ->NowContains(value)) { | |
401 Handle<HeapType> value_type(value->OptimalType( | |
402 isolate(), expected_representation)); | |
403 Map::GeneralizeFieldType(target, descriptor, | |
404 expected_representation, value_type); | |
405 } | |
406 DCHECK(target->instance_descriptors()->GetFieldType( | |
407 descriptor)->NowContains(value)); | |
408 properties.Add(value, zone()); | |
409 map = target; | |
410 descriptor++; | |
411 continue; | |
412 } else { | |
413 transitioning = false; | |
414 } | |
415 } | |
416 | |
417 // Commit the intermediate state to the object and stop transitioning. | |
418 CommitStateToJsonObject(json_object, map, &properties); | |
419 } else { | |
420 key = ParseJsonInternalizedString(); | 471 key = ParseJsonInternalizedString(); |
421 if (key.is_null() || c0_ != ':') return ReportUnexpectedCharacter(); | 472 if (key.is_null() || c0_ != ':') return ReportUnexpectedCharacter(); |
422 | 473 |
423 AdvanceSkipWhitespace(); | 474 AdvanceSkipWhitespace(); |
424 value = ParseJsonValue(); | 475 value = ParseJsonValue(); |
425 if (value.is_null()) return ReportUnexpectedCharacter(); | 476 if (value.is_null()) return ReportUnexpectedCharacter(); |
| 477 |
| 478 Runtime::DefineObjectProperty(json_object, key, value, NONE).Check(); |
426 } | 479 } |
| 480 } |
427 | 481 |
428 Runtime::DefineObjectProperty(json_object, key, value, NONE).Check(); | |
429 } while (MatchSkipWhiteSpace(',')); | |
430 if (c0_ != '}') { | 482 if (c0_ != '}') { |
431 return ReportUnexpectedCharacter(); | 483 return ReportUnexpectedCharacter(); |
432 } | 484 } |
433 | |
434 // If we transitioned until the very end, transition the map now. | |
435 if (transitioning) { | |
436 CommitStateToJsonObject(json_object, map, &properties); | |
437 } | |
438 } | 485 } |
439 AdvanceSkipWhitespace(); | 486 AdvanceSkipWhitespace(); |
440 return scope.CloseAndEscape(json_object); | 487 return scope.CloseAndEscape(json_object); |
441 } | 488 } |
442 | 489 |
443 | 490 |
444 template <bool seq_one_byte> | 491 template <bool seq_one_byte> |
445 void JsonParser<seq_one_byte>::CommitStateToJsonObject( | 492 void JsonParser<seq_one_byte>::CommitStateToJsonObject( |
446 Handle<JSObject> json_object, Handle<Map> map, | 493 Handle<JSObject> json_object, Handle<Map> map, |
447 ZoneList<Handle<Object> >* properties) { | 494 ZoneList<Handle<Object> >* properties) { |
(...skipping 345 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
793 | 840 |
794 DCHECK_EQ('"', c0_); | 841 DCHECK_EQ('"', c0_); |
795 // Advance past the last '"'. | 842 // Advance past the last '"'. |
796 AdvanceSkipWhitespace(); | 843 AdvanceSkipWhitespace(); |
797 return result; | 844 return result; |
798 } | 845 } |
799 | 846 |
800 } } // namespace v8::internal | 847 } } // namespace v8::internal |
801 | 848 |
802 #endif // V8_JSON_PARSER_H_ | 849 #endif // V8_JSON_PARSER_H_ |
OLD | NEW |