| 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 |