| 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 #library("json"); | 5 #library("json"); |
| 6 | 6 |
| 7 // Pure Dart implementation of JSON protocol. | 7 // Pure Dart implementation of JSON protocol. |
| 8 | 8 |
| 9 /** | 9 /** |
| 10 * Utility class to parse JSON and serialize objects to JSON. | 10 * Utility class to parse JSON and serialize objects to JSON. |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 107 } | 107 } |
| 108 } | 108 } |
| 109 | 109 |
| 110 typedef bool Predicate(int c); | 110 typedef bool Predicate(int c); |
| 111 | 111 |
| 112 class JsonTokenizer { | 112 class JsonTokenizer { |
| 113 static final int BACKSPACE = 8; // '\b'.charCodeAt(0) | 113 static final int BACKSPACE = 8; // '\b'.charCodeAt(0) |
| 114 static final int TAB = 9; // '\t'.charCodeAt(0) | 114 static final int TAB = 9; // '\t'.charCodeAt(0) |
| 115 static final int NEW_LINE = 10; // '\n'.charCodeAt(0) | 115 static final int NEW_LINE = 10; // '\n'.charCodeAt(0) |
| 116 static final int FORM_FEED = 12; // '\f'.charCodeAt(0) | 116 static final int FORM_FEED = 12; // '\f'.charCodeAt(0) |
| 117 static final int LINE_FEED = 13; // '\r'.charCodeAt(0) | 117 static final int CARRIAGE_RETURN = 13; // '\r'.charCodeAt(0) |
| 118 static final int SPACE = 32; // ' '.charCodeAt(0) | 118 static final int SPACE = 32; // ' '.charCodeAt(0) |
| 119 static final int QUOTE = 34; // '"'.charCodeAt(0) | 119 static final int QUOTE = 34; // '"'.charCodeAt(0) |
| 120 static final int PLUS = 43; // '+'.charCodeAt(0) | 120 static final int PLUS = 43; // '+'.charCodeAt(0) |
| 121 static final int COMMA = 44; // ','.charCodeAt(0) | 121 static final int COMMA = 44; // ','.charCodeAt(0) |
| 122 static final int MINUS = 45; // '-'.charCodeAt(0) | 122 static final int MINUS = 45; // '-'.charCodeAt(0) |
| 123 static final int DOT = 46; // '.'.charCodeAt(0) | 123 static final int DOT = 46; // '.'.charCodeAt(0) |
| 124 static final int SLASH = 47; // '/'.charCodeAt(0) | 124 static final int SLASH = 47; // '/'.charCodeAt(0) |
| 125 static final int ZERO = 48; // '0'.charCodeAt(0) | 125 static final int ZERO = 48; // '0'.charCodeAt(0) |
| 126 static final int NINE = 57; // '9'.charCodeAt(0) | 126 static final int NINE = 57; // '9'.charCodeAt(0) |
| 127 static final int COLON = 58; // ':'.charCodeAt(0) | 127 static final int COLON = 58; // ':'.charCodeAt(0) |
| 128 static final int A_BIG = 65; // 'A'.charCodeAt(0) | 128 static final int A_BIG = 65; // 'A'.charCodeAt(0) |
| 129 static final int E_BIG = 69; // 'E'.charCodeAt(0) | 129 static final int E_BIG = 69; // 'E'.charCodeAt(0) |
| 130 static final int Z_BIG = 90; // 'Z'.charCodeAt(0) | 130 static final int Z_BIG = 90; // 'Z'.charCodeAt(0) |
| 131 static final int LBRACKET = 91; // '['.charCodeAt(0) | 131 static final int LBRACKET = 91; // '['.charCodeAt(0) |
| 132 static final int BACKSLASH = 92; // '\\'.charCodeAt(0) | 132 static final int BACKSLASH = 92; // '\\'.charCodeAt(0) |
| 133 static final int RBRACKET = 93; // ']'.charCodeAt(0) | 133 static final int RBRACKET = 93; // ']'.charCodeAt(0) |
| 134 static final int A_SMALL = 97; // 'a'.charCodeAt(0) | 134 static final int A_SMALL = 97; // 'a'.charCodeAt(0) |
| 135 static final int B_SMALL = 98; // 'b'.charCodeAt(0) | 135 static final int B_SMALL = 98; // 'b'.charCodeAt(0) |
| 136 static final int E_SMALL = 101; // 'e'.charCodeAt(0) | 136 static final int E_SMALL = 101; // 'e'.charCodeAt(0) |
| 137 static final int F_SMALL = 102; // 'f'.charCodeAt(0) |
| 137 static final int N_SMALL = 110; // 'n'.charCodeAt(0) | 138 static final int N_SMALL = 110; // 'n'.charCodeAt(0) |
| 138 static final int R_SMALL = 114; // 'r'.charCodeAt(0) | 139 static final int R_SMALL = 114; // 'r'.charCodeAt(0) |
| 140 static final int T_SMALL = 116; // 't'.charCodeAt(0) |
| 141 static final int U_SMALL = 117; // 'u'.charCodeAt(0) |
| 139 static final int Z_SMALL = 122; // 'z'.charCodeAt(0) | 142 static final int Z_SMALL = 122; // 'z'.charCodeAt(0) |
| 140 static final int LBRACE = 123; // '{'.charCodeAt(0) | 143 static final int LBRACE = 123; // '{'.charCodeAt(0) |
| 141 static final int RBRACE = 125; // '}'.charCodeAt(0) | 144 static final int RBRACE = 125; // '}'.charCodeAt(0) |
| 142 | 145 |
| 143 JsonTokenizer(String s) : _s = s + ' ', _pos = 0, _len = s.length + 1 {} | 146 JsonTokenizer(String s) : _s = s + ' ', _pos = 0, _len = s.length + 1 {} |
| 144 | 147 |
| 145 /** | 148 /** |
| 146 * Fetches next token or [:null:] if the stream has been exhausted. | 149 * Fetches next token or [:null:] if the stream has been exhausted. |
| 147 */ | 150 */ |
| 148 JsonToken next() { | 151 JsonToken next() { |
| (...skipping 30 matching lines...) Expand all Loading... |
| 179 case '/': | 182 case '/': |
| 180 c = SLASH; | 183 c = SLASH; |
| 181 break; | 184 break; |
| 182 case 'b': | 185 case 'b': |
| 183 c = BACKSPACE; | 186 c = BACKSPACE; |
| 184 break; | 187 break; |
| 185 case 'n': | 188 case 'n': |
| 186 c = NEW_LINE; | 189 c = NEW_LINE; |
| 187 break; | 190 break; |
| 188 case 'r': | 191 case 'r': |
| 189 c = LINE_FEED; | 192 c = CARRIAGE_RETURN; |
| 190 break; | 193 break; |
| 191 case 'f': | 194 case 'f': |
| 192 c = FORM_FEED; | 195 c = FORM_FEED; |
| 193 break; | 196 break; |
| 194 case 't': | 197 case 't': |
| 195 c = TAB; | 198 c = TAB; |
| 196 break; | 199 break; |
| 197 case 'u': | 200 case 'u': |
| 198 if (_pos + 5 > _len) { | 201 if (_pos + 5 > _len) { |
| 199 throw 'Invalid unicode esacape sequence: \\' + | 202 throw 'Invalid unicode esacape sequence: \\' + |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 328 while (_pos < _len && predicate(_s.charCodeAt(_pos))) { | 331 while (_pos < _len && predicate(_s.charCodeAt(_pos))) { |
| 329 _pos++; | 332 _pos++; |
| 330 } | 333 } |
| 331 if (_pos == _len) { | 334 if (_pos == _len) { |
| 332 throw errorMsg; | 335 throw errorMsg; |
| 333 } | 336 } |
| 334 } | 337 } |
| 335 | 338 |
| 336 // TODO other kind of whitespace. | 339 // TODO other kind of whitespace. |
| 337 static bool isWhitespace(int c) { | 340 static bool isWhitespace(int c) { |
| 338 return c == SPACE || c == TAB || c == NEW_LINE || c == LINE_FEED; | 341 return c == SPACE || c == TAB || c == NEW_LINE || c == CARRIAGE_RETURN; |
| 339 } | 342 } |
| 340 static bool isDigit(int c) { | 343 static bool isDigit(int c) { |
| 341 return (ZERO <= c) && (c <= NINE); | 344 return (ZERO <= c) && (c <= NINE); |
| 342 } | 345 } |
| 343 static bool isLetter(int c) { | 346 static bool isLetter(int c) { |
| 344 return ((A_SMALL <= c) && (c <= Z_SMALL)) || ((A_BIG <= c) && (c <= Z_BIG))
; | 347 return ((A_SMALL <= c) && (c <= Z_SMALL)) || ((A_BIG <= c) && (c <= Z_BIG))
; |
| 345 } | 348 } |
| 346 } | 349 } |
| 347 | 350 |
| 348 class JsonParser { | 351 class JsonParser { |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 486 return x.toString(); | 489 return x.toString(); |
| 487 | 490 |
| 488 case x is double: | 491 case x is double: |
| 489 return x.toString(); | 492 return x.toString(); |
| 490 | 493 |
| 491 default: | 494 default: |
| 492 return x.toDouble().toString(); | 495 return x.toDouble().toString(); |
| 493 } | 496 } |
| 494 } | 497 } |
| 495 | 498 |
| 496 // TODO: add others. | 499 // ('0' + x) or ('a' + x - 10) |
| 497 static bool _needsEscape(int charCode) { | 500 static int _hexDigit(int x) => x < 10 ? 48 + x : 87 + x; |
| 498 return JsonTokenizer.QUOTE == charCode || JsonTokenizer.BACKSLASH == charCod
e | |
| 499 || JsonTokenizer.NEW_LINE == charCode || JsonTokenizer.LINE_FEED == charCo
de; | |
| 500 } | |
| 501 | 501 |
| 502 static void _escape(StringBuffer sb, String s) { | 502 static void _escape(StringBuffer sb, String s) { |
| 503 // TODO: support \u code points. | |
| 504 // TODO: use writeCodePoint when implemented. | |
| 505 // TODO: use for each if implemented. | |
| 506 final int length = s.length; | 503 final int length = s.length; |
| 507 bool needsEscape = false; | 504 bool needsEscape = false; |
| 508 final charCodes = new List<int>(); | 505 final charCodes = new List<int>(); |
| 509 for (int i = 0; i < length; i++) { | 506 for (int i = 0; i < length; i++) { |
| 510 int charCode = s.charCodeAt(i); | 507 int charCode = s.charCodeAt(i); |
| 511 if (_needsEscape(charCode)) { | 508 if (charCode < 32) { |
| 509 needsEscape = true; |
| 512 charCodes.add(JsonTokenizer.BACKSLASH); | 510 charCodes.add(JsonTokenizer.BACKSLASH); |
| 511 switch (charCode) { |
| 512 case JsonTokenizer.BACKSPACE: |
| 513 charCodes.add(JsonTokenizer.B_SMALL); |
| 514 break; |
| 515 case JsonTokenizer.TAB: |
| 516 charCodes.add(JsonTokenizer.T_SMALL); |
| 517 break; |
| 518 case JsonTokenizer.NEW_LINE: |
| 519 charCodes.add(JsonTokenizer.N_SMALL); |
| 520 break; |
| 521 case JsonTokenizer.FORM_FEED: |
| 522 charCodes.add(JsonTokenizer.F_SMALL); |
| 523 break; |
| 524 case JsonTokenizer.CARRIAGE_RETURN: |
| 525 charCodes.add(JsonTokenizer.R_SMALL); |
| 526 break; |
| 527 default: |
| 528 charCodes.add(JsonTokenizer.U_SMALL); |
| 529 charCodes.add(_hexDigit((charCode >> 12) & 0xf)); |
| 530 charCodes.add(_hexDigit((charCode >> 8) & 0xf)); |
| 531 charCodes.add(_hexDigit((charCode >> 4) & 0xf)); |
| 532 charCodes.add(_hexDigit(charCode & 0xf)); |
| 533 break; |
| 534 } |
| 535 } else if (charCode == JsonTokenizer.QUOTE || |
| 536 charCode == JsonTokenizer.BACKSLASH) { |
| 513 needsEscape = true; | 537 needsEscape = true; |
| 514 | 538 charCodes.add(JsonTokenizer.BACKSLASH); |
| 515 if (JsonTokenizer.NEW_LINE == charCode) { | 539 charCodes.add(charCode); |
| 516 charCode = JsonTokenizer.N_SMALL; | 540 } else { |
| 517 } else if (JsonTokenizer.LINE_FEED == charCode) { | 541 charCodes.add(charCode); |
| 518 charCode = JsonTokenizer.R_SMALL; | |
| 519 } | |
| 520 } | 542 } |
| 521 charCodes.add(charCode); | |
| 522 } | 543 } |
| 523 sb.add(needsEscape ? new String.fromCharCodes(charCodes) : s); | 544 sb.add(needsEscape ? new String.fromCharCodes(charCodes) : s); |
| 524 } | 545 } |
| 525 | 546 |
| 526 void _checkCycle(final object) { | 547 void _checkCycle(final object) { |
| 527 // TODO: use Iterables. | 548 // TODO: use Iterables. |
| 528 for (int i = 0; i < _seen.length; i++) { | 549 for (int i = 0; i < _seen.length; i++) { |
| 529 if (_seen[i] === object) { | 550 if (_seen[i] === object) { |
| 530 throw 'Cyclic structure'; | 551 throw 'Cyclic structure'; |
| 531 } | 552 } |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 592 }); | 613 }); |
| 593 _sb.add('}'); | 614 _sb.add('}'); |
| 594 _seen.removeLast(); | 615 _seen.removeLast(); |
| 595 return; | 616 return; |
| 596 | 617 |
| 597 default: | 618 default: |
| 598 throw const JsonUnsupportedObjectType(); | 619 throw const JsonUnsupportedObjectType(); |
| 599 } | 620 } |
| 600 } | 621 } |
| 601 } | 622 } |
| OLD | NEW |