| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 library dart.json; | 5 library dart.json; |
| 6 | 6 |
| 7 // JSON parsing and serialization. | 7 // JSON parsing and serialization. |
| 8 | 8 |
| 9 /** | 9 /** |
| 10 * Error thrown by JSON serialization if an object cannot be serialized. | 10 * Error thrown by JSON serialization if an object cannot be serialized. |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 103 * serialized, the new values may or may not be reflected in the result. | 103 * serialized, the new values may or may not be reflected in the result. |
| 104 */ | 104 */ |
| 105 String stringify(Object object) { | 105 String stringify(Object object) { |
| 106 return _JsonStringifier.stringify(object); | 106 return _JsonStringifier.stringify(object); |
| 107 } | 107 } |
| 108 | 108 |
| 109 /** | 109 /** |
| 110 * Serializes [object] into [output] stream. | 110 * Serializes [object] into [output] stream. |
| 111 * | 111 * |
| 112 * Performs the same operations as [stringify] but outputs the resulting | 112 * Performs the same operations as [stringify] but outputs the resulting |
| 113 * string to an existing [StringBuffer] instead of creating a new [String]. | 113 * string to an existing [StringSink] instead of creating a new [String]. |
| 114 * | 114 * |
| 115 * If serialization fails by throwing, some data might have been added to | 115 * If serialization fails by throwing, some data might have been added to |
| 116 * [output], but it won't contain valid JSON text. | 116 * [output], but it won't contain valid JSON text. |
| 117 */ | 117 */ |
| 118 void printOn(Object object, StringBuffer output) { | 118 void printOn(Object object, StringSink output) { |
| 119 return _JsonStringifier.printOn(object, output); | 119 return _JsonStringifier.printOn(object, output); |
| 120 } | 120 } |
| 121 | 121 |
| 122 //// Implementation /////////////////////////////////////////////////////////// | 122 //// Implementation /////////////////////////////////////////////////////////// |
| 123 | 123 |
| 124 // Simple API for JSON parsing. | 124 // Simple API for JSON parsing. |
| 125 | 125 |
| 126 abstract class JsonListener { | 126 abstract class JsonListener { |
| 127 void handleString(String value) {} | 127 void handleString(String value) {} |
| 128 void handleNumber(num value) {} | 128 void handleNumber(num value) {} |
| (...skipping 527 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 656 slice = "'${source.substring(position)}'"; | 656 slice = "'${source.substring(position)}'"; |
| 657 } else { | 657 } else { |
| 658 slice = "'${source.substring(position, sliceEnd)}...'"; | 658 slice = "'${source.substring(position, sliceEnd)}...'"; |
| 659 } | 659 } |
| 660 throw new FormatException("Unexpected character at $position: $slice"); | 660 throw new FormatException("Unexpected character at $position: $slice"); |
| 661 } | 661 } |
| 662 } | 662 } |
| 663 | 663 |
| 664 | 664 |
| 665 class _JsonStringifier { | 665 class _JsonStringifier { |
| 666 StringBuffer sb; | 666 StringSink sink; |
| 667 List<Object> seen; // TODO: that should be identity set. | 667 List<Object> seen; // TODO: that should be identity set. |
| 668 | 668 |
| 669 _JsonStringifier(this.sb) : seen = []; | 669 _JsonStringifier(this.sink) : seen = []; |
| 670 | 670 |
| 671 static String stringify(final object) { | 671 static String stringify(final object) { |
| 672 StringBuffer output = new StringBuffer(); | 672 StringBuffer output = new StringBuffer(); |
| 673 _JsonStringifier stringifier = new _JsonStringifier(output); | 673 _JsonStringifier stringifier = new _JsonStringifier(output); |
| 674 stringifier.stringifyValue(object); | 674 stringifier.stringifyValue(object); |
| 675 return output.toString(); | 675 return output.toString(); |
| 676 } | 676 } |
| 677 | 677 |
| 678 static void printOn(final object, StringBuffer output) { | 678 static void printOn(final object, StringSink output) { |
| 679 _JsonStringifier stringifier = new _JsonStringifier(output); | 679 _JsonStringifier stringifier = new _JsonStringifier(output); |
| 680 stringifier.stringifyValue(object); | 680 stringifier.stringifyValue(object); |
| 681 } | 681 } |
| 682 | 682 |
| 683 static String numberToString(num x) { | 683 static String numberToString(num x) { |
| 684 return x.toString(); | 684 return x.toString(); |
| 685 } | 685 } |
| 686 | 686 |
| 687 // ('0' + x) or ('a' + x - 10) | 687 // ('0' + x) or ('a' + x - 10) |
| 688 static int hexDigit(int x) => x < 10 ? 48 + x : 87 + x; | 688 static int hexDigit(int x) => x < 10 ? 48 + x : 87 + x; |
| 689 | 689 |
| 690 static void escape(StringBuffer sb, String s) { | 690 static void escape(StringSink sb, String s) { |
| 691 final int length = s.length; | 691 final int length = s.length; |
| 692 bool needsEscape = false; | 692 bool needsEscape = false; |
| 693 final charCodes = new List<int>(); | 693 final charCodes = new List<int>(); |
| 694 for (int i = 0; i < length; i++) { | 694 for (int i = 0; i < length; i++) { |
| 695 int charCode = s.codeUnitAt(i); | 695 int charCode = s.codeUnitAt(i); |
| 696 if (charCode < 32) { | 696 if (charCode < 32) { |
| 697 needsEscape = true; | 697 needsEscape = true; |
| 698 charCodes.add(JsonParser.BACKSLASH); | 698 charCodes.add(JsonParser.BACKSLASH); |
| 699 switch (charCode) { | 699 switch (charCode) { |
| 700 case JsonParser.BACKSPACE: | 700 case JsonParser.BACKSPACE: |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 762 | 762 |
| 763 /** | 763 /** |
| 764 * Serializes a [num], [String], [bool], [Null], [List] or [Map] value. | 764 * Serializes a [num], [String], [bool], [Null], [List] or [Map] value. |
| 765 * | 765 * |
| 766 * Returns true if the value is one of these types, and false if not. | 766 * Returns true if the value is one of these types, and false if not. |
| 767 * If a value is both a [List] and a [Map], it's serialized as a [List]. | 767 * If a value is both a [List] and a [Map], it's serialized as a [List]. |
| 768 */ | 768 */ |
| 769 bool stringifyJsonValue(final object) { | 769 bool stringifyJsonValue(final object) { |
| 770 if (object is num) { | 770 if (object is num) { |
| 771 // TODO: use writeOn. | 771 // TODO: use writeOn. |
| 772 sb.write(numberToString(object)); | 772 sink.write(numberToString(object)); |
| 773 return true; | 773 return true; |
| 774 } else if (identical(object, true)) { | 774 } else if (identical(object, true)) { |
| 775 sb.write('true'); | 775 sink.write('true'); |
| 776 return true; | 776 return true; |
| 777 } else if (identical(object, false)) { | 777 } else if (identical(object, false)) { |
| 778 sb.write('false'); | 778 sink.write('false'); |
| 779 return true; | 779 return true; |
| 780 } else if (object == null) { | 780 } else if (object == null) { |
| 781 sb.write('null'); | 781 sink.write('null'); |
| 782 return true; | 782 return true; |
| 783 } else if (object is String) { | 783 } else if (object is String) { |
| 784 sb.write('"'); | 784 sink.write('"'); |
| 785 escape(sb, object); | 785 escape(sink, object); |
| 786 sb.write('"'); | 786 sink.write('"'); |
| 787 return true; | 787 return true; |
| 788 } else if (object is List) { | 788 } else if (object is List) { |
| 789 checkCycle(object); | 789 checkCycle(object); |
| 790 List a = object; | 790 List a = object; |
| 791 sb.write('['); | 791 sink.write('['); |
| 792 if (a.length > 0) { | 792 if (a.length > 0) { |
| 793 stringifyValue(a[0]); | 793 stringifyValue(a[0]); |
| 794 // TODO: switch to Iterables. | 794 // TODO: switch to Iterables. |
| 795 for (int i = 1; i < a.length; i++) { | 795 for (int i = 1; i < a.length; i++) { |
| 796 sb.write(','); | 796 sink.write(','); |
| 797 stringifyValue(a[i]); | 797 stringifyValue(a[i]); |
| 798 } | 798 } |
| 799 } | 799 } |
| 800 sb.write(']'); | 800 sink.write(']'); |
| 801 seen.removeLast(); | 801 seen.removeLast(); |
| 802 return true; | 802 return true; |
| 803 } else if (object is Map) { | 803 } else if (object is Map) { |
| 804 checkCycle(object); | 804 checkCycle(object); |
| 805 Map<String, Object> m = object; | 805 Map<String, Object> m = object; |
| 806 sb.write('{'); | 806 sink.write('{'); |
| 807 bool first = true; | 807 bool first = true; |
| 808 m.forEach((String key, Object value) { | 808 m.forEach((String key, Object value) { |
| 809 if (!first) { | 809 if (!first) { |
| 810 sb.write(',"'); | 810 sink.write(',"'); |
| 811 } else { | 811 } else { |
| 812 sb.write('"'); | 812 sink.write('"'); |
| 813 } | 813 } |
| 814 escape(sb, key); | 814 escape(sink, key); |
| 815 sb.write('":'); | 815 sink.write('":'); |
| 816 stringifyValue(value); | 816 stringifyValue(value); |
| 817 first = false; | 817 first = false; |
| 818 }); | 818 }); |
| 819 sb.write('}'); | 819 sink.write('}'); |
| 820 seen.removeLast(); | 820 seen.removeLast(); |
| 821 return true; | 821 return true; |
| 822 } else { | 822 } else { |
| 823 return false; | 823 return false; |
| 824 } | 824 } |
| 825 } | 825 } |
| 826 } | 826 } |
| OLD | NEW |