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