OLD | NEW |
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 // Pure Dart implementation of JSON protocol. | 5 // Pure Dart implementation of JSON protocol. |
6 | 6 |
7 /** | 7 /** |
8 * Utility class to parse JSON and serialize objects to JSON. | 8 * Utility class to parse JSON and serialize objects to JSON. |
9 */ | 9 */ |
10 class JSON { | 10 class JSON { |
(...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
337 } | 337 } |
338 | 338 |
339 final JsonTokenizer _tokenizer; | 339 final JsonTokenizer _tokenizer; |
340 | 340 |
341 JsonParser._internal(String json) : _tokenizer = new JsonTokenizer(json) {} | 341 JsonParser._internal(String json) : _tokenizer = new JsonTokenizer(json) {} |
342 | 342 |
343 _parseToplevel() { | 343 _parseToplevel() { |
344 JsonToken token = _tokenizer.next(); | 344 JsonToken token = _tokenizer.next(); |
345 final result = _parseValue(token); | 345 final result = _parseValue(token); |
346 token = _tokenizer.next(); | 346 token = _tokenizer.next(); |
347 if (token !== null) { | 347 if (token != null) { |
348 throw 'Junk at the end'; | 348 throw 'Junk at the end'; |
349 } | 349 } |
350 return result; | 350 return result; |
351 } | 351 } |
352 | 352 |
353 _parseValue(final JsonToken token) { | 353 _parseValue(final JsonToken token) { |
354 if (token === null) { | 354 if (token == null) { |
355 throw 'Nothing to parse'; | 355 throw 'Nothing to parse'; |
356 } | 356 } |
357 switch (token.kind) { | 357 switch (token.kind) { |
358 case JsonToken.STRING: | 358 case JsonToken.STRING: |
359 return token.str; | 359 return token.str; |
360 | 360 |
361 case JsonToken.NUMBER: | 361 case JsonToken.NUMBER: |
362 return token.number; | 362 return token.number; |
363 | 363 |
364 case JsonToken.NULL: | 364 case JsonToken.NULL: |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
407 _parseSequence(JsonToken.RBRACKET, (JsonToken token) { | 407 _parseSequence(JsonToken.RBRACKET, (JsonToken token) { |
408 final value = _parseValue(token); | 408 final value = _parseValue(token); |
409 array.add(value); | 409 array.add(value); |
410 }); | 410 }); |
411 | 411 |
412 return array; | 412 return array; |
413 } | 413 } |
414 | 414 |
415 void _parseSequence(int endTokenKind, void parseElement(JsonToken token)) { | 415 void _parseSequence(int endTokenKind, void parseElement(JsonToken token)) { |
416 JsonToken token = _tokenizer.next(); | 416 JsonToken token = _tokenizer.next(); |
417 if (token === null) { | 417 if (token == null) { |
418 throw 'Unexpected end of stream'; | 418 throw 'Unexpected end of stream'; |
419 } | 419 } |
420 if (token.kind == endTokenKind) { | 420 if (token.kind == endTokenKind) { |
421 return; | 421 return; |
422 } | 422 } |
423 | 423 |
424 parseElement(token); | 424 parseElement(token); |
425 | 425 |
426 token = _tokenizer.next(); | 426 token = _tokenizer.next(); |
427 if (token === null) { | 427 if (token == null) { |
428 throw 'Expected either comma or terminator'; | 428 throw 'Expected either comma or terminator'; |
429 } | 429 } |
430 while (token.kind != endTokenKind) { | 430 while (token.kind != endTokenKind) { |
431 _assertTokenKind(token, JsonToken.COMMA); | 431 _assertTokenKind(token, JsonToken.COMMA); |
432 | 432 |
433 token = _tokenizer.next(); | 433 token = _tokenizer.next(); |
434 parseElement(token); | 434 parseElement(token); |
435 | 435 |
436 token = _tokenizer.next(); | 436 token = _tokenizer.next(); |
437 } | 437 } |
438 } | 438 } |
439 | 439 |
440 void _assertTokenKind(JsonToken token, int kind) { | 440 void _assertTokenKind(JsonToken token, int kind) { |
441 if (token === null || token.kind != kind) { | 441 if (token == null || token.kind != kind) { |
442 throw 'Unexpected token kind: token = ${token}, expected kind = ${kind}'; | 442 throw 'Unexpected token kind: token = ${token}, expected kind = ${kind}'; |
443 } | 443 } |
444 } | 444 } |
445 | 445 |
446 // TODO: consider factor out error throwing code and build more complicated | 446 // TODO: consider factor out error throwing code and build more complicated |
447 // data structure to provide more info for a caller. | 447 // data structure to provide more info for a caller. |
448 } | 448 } |
449 | 449 |
450 // TODO: proper base class. | 450 // TODO: proper base class. |
451 class JsonUnsupportedObjectType { | 451 class JsonUnsupportedObjectType { |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
499 needsEscape = true; | 499 needsEscape = true; |
500 } | 500 } |
501 charCodes.add(charCode); | 501 charCodes.add(charCode); |
502 } | 502 } |
503 sb.add(needsEscape ? new String.fromCharCodes(charCodes) : s); | 503 sb.add(needsEscape ? new String.fromCharCodes(charCodes) : s); |
504 } | 504 } |
505 | 505 |
506 void _checkCycle(final object) { | 506 void _checkCycle(final object) { |
507 // TODO: use Iterables. | 507 // TODO: use Iterables. |
508 for (int i = 0; i < _seen.length; i++) { | 508 for (int i = 0; i < _seen.length; i++) { |
509 if (_seen[i] === object) { | 509 if (identical(_seen[i], object)) { |
510 throw 'Cyclic structure'; | 510 throw 'Cyclic structure'; |
511 } | 511 } |
512 } | 512 } |
513 _seen.add(object); | 513 _seen.add(object); |
514 } | 514 } |
515 | 515 |
516 void _stringify(final object) { | 516 void _stringify(final object) { |
517 if (object is num) { | 517 if (object is num) { |
518 // TODO: use writeOn. | 518 // TODO: use writeOn. |
519 _sb.add(_numberToString(object)); | 519 _sb.add(_numberToString(object)); |
520 return; | 520 return; |
521 } else if (object === true) { | 521 } else if (identical(object, true)) { |
522 _sb.add('true'); | 522 _sb.add('true'); |
523 return; | 523 return; |
524 } else if (object === false) { | 524 } else if (identical(object, false)) { |
525 _sb.add('false'); | 525 _sb.add('false'); |
526 return; | 526 return; |
527 } else if (object === null) { | 527 } else if (object == null) { |
528 _sb.add('null'); | 528 _sb.add('null'); |
529 return; | 529 return; |
530 } else if (object is String) { | 530 } else if (object is String) { |
531 _sb.add('"'); | 531 _sb.add('"'); |
532 _escape(_sb, object); | 532 _escape(_sb, object); |
533 _sb.add('"'); | 533 _sb.add('"'); |
534 return; | 534 return; |
535 } else if (object is List) { | 535 } else if (object is List) { |
536 _checkCycle(object); | 536 _checkCycle(object); |
537 List a = object; | 537 List a = object; |
(...skipping 22 matching lines...) Expand all Loading... |
560 _sb.add(','); | 560 _sb.add(','); |
561 } | 561 } |
562 }); | 562 }); |
563 _sb.add('}'); | 563 _sb.add('}'); |
564 return; | 564 return; |
565 } else { | 565 } else { |
566 throw const JsonUnsupportedObjectType(); | 566 throw const JsonUnsupportedObjectType(); |
567 } | 567 } |
568 } | 568 } |
569 } | 569 } |
OLD | NEW |