Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(106)

Side by Side Diff: runtime/lib/convert_patch.dart

Issue 1150033013: Clean up JSON parsing code. (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, 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 import "dart:_internal" show POWERS_OF_TEN; 5 import "dart:_internal" show POWERS_OF_TEN;
6 6
7 // JSON conversion. 7 // JSON conversion.
8 8
9 patch _parseJson(String json, reviver(var key, var value)) { 9 patch _parseJson(String json, reviver(var key, var value)) {
10 _BuildJsonListener listener; 10 _BuildJsonListener listener;
(...skipping 13 matching lines...) Expand all
24 patch class Utf8Decoder { 24 patch class Utf8Decoder {
25 /* patch */ 25 /* patch */
26 Converter<List<int>, dynamic> fuse(Converter<String, dynamic> next) { 26 Converter<List<int>, dynamic> fuse(Converter<String, dynamic> next) {
27 if (next is JsonDecoder) { 27 if (next is JsonDecoder) {
28 return new _JsonUtf8Decoder(next._reviver, this._allowMalformed); 28 return new _JsonUtf8Decoder(next._reviver, this._allowMalformed);
29 } 29 }
30 // TODO(lrn): Recognize a fused decoder where the next step is JsonDecoder. 30 // TODO(lrn): Recognize a fused decoder where the next step is JsonDecoder.
31 return super.fuse(next); 31 return super.fuse(next);
32 } 32 }
33 33
34 // Allow intercepting of UTF8 decoding when builtin lists are passed. 34 // Allow intercepting of UTF-8 decoding when built-in lists are passed.
35 /* patch */ 35 /* patch */
36 static String _convertIntercepted( 36 static String _convertIntercepted(
37 bool allowMalformed, List<int> codeUnits, int start, int end) { 37 bool allowMalformed, List<int> codeUnits, int start, int end) {
38 return null; // This call was not intercepted. 38 return null; // This call was not intercepted.
39 } 39 }
40 } 40 }
41 41
42 class _JsonUtf8Decoder extends Converter<List<int>, Object> { 42 class _JsonUtf8Decoder extends Converter<List<int>, Object> {
43 final _Reviver _reviver; 43 final _Reviver _reviver;
44 final bool _allowMalformed; 44 final bool _allowMalformed;
(...skipping 25 matching lines...) Expand all
70 void handleNumber(num value) {} 70 void handleNumber(num value) {}
71 void handleBool(bool value) {} 71 void handleBool(bool value) {}
72 void handleNull() {} 72 void handleNull() {}
73 void beginObject() {} 73 void beginObject() {}
74 void propertyName() {} 74 void propertyName() {}
75 void propertyValue() {} 75 void propertyValue() {}
76 void endObject() {} 76 void endObject() {}
77 void beginArray() {} 77 void beginArray() {}
78 void arrayElement() {} 78 void arrayElement() {}
79 void endArray() {} 79 void endArray() {}
80
81 /**
82 * Read out the final result of parsing a JSON string.
83 *
84 * Must only be called when the entire input has been parsed.
85 */
86 get result;
80 } 87 }
81 88
82 /** 89 /**
83 * A [_JsonListener] that builds data objects from the parser events. 90 * A [_JsonListener] that builds data objects from the parser events.
84 * 91 *
85 * This is a simple stack-based object builder. It keeps the most recently 92 * This is a simple stack-based object builder. It keeps the most recently
86 * seen value in a variable, and uses it depending on the following event. 93 * seen value in a variable, and uses it depending on the following event.
87 */ 94 */
88 class _BuildJsonListener extends _JsonListener { 95 class _BuildJsonListener extends _JsonListener {
89 /** 96 /**
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after
261 // Starting a new array or object will push the current state. The "pop" 268 // Starting a new array or object will push the current state. The "pop"
262 // above means restoring this state and then marking it as an ended value. 269 // above means restoring this state and then marking it as an ended value.
263 // X means generic handling, @ means special handling for just that 270 // X means generic handling, @ means special handling for just that
264 // state - that is, values are handled generically, only punctuation 271 // state - that is, values are handled generically, only punctuation
265 // cares about the current state. 272 // cares about the current state.
266 // Values for states are chosen so bits 0 and 1 tell whether 273 // Values for states are chosen so bits 0 and 1 tell whether
267 // a string/value is allowed, and setting bits 0 through 2 after a value 274 // a string/value is allowed, and setting bits 0 through 2 after a value
268 // gets to the next state (not empty, doesn't allow a value). 275 // gets to the next state (not empty, doesn't allow a value).
269 276
270 // State building-block constants. 277 // State building-block constants.
271 static const int INSIDE_ARRAY = 1; 278 static const int TOP_LEVEL = 0;
272 static const int INSIDE_OBJECT = 2; 279 static const int INSIDE_ARRAY = 1;
273 static const int AFTER_COLON = 3; // Always inside object. 280 static const int INSIDE_OBJECT = 2;
281 static const int AFTER_COLON = 3; // Always inside object.
274 282
275 static const int ALLOW_STRING_MASK = 8; // Allowed if zero. 283 static const int ALLOW_STRING_MASK = 8; // Allowed if zero.
276 static const int ALLOW_VALUE_MASK = 4; // Allowed if zero. 284 static const int ALLOW_VALUE_MASK = 4; // Allowed if zero.
277 static const int ALLOW_VALUE = 0; 285 static const int ALLOW_VALUE = 0;
278 static const int STRING_ONLY = 4; 286 static const int STRING_ONLY = 4;
279 static const int NO_VALUES = 12; 287 static const int NO_VALUES = 12;
280 288
281 // Objects and arrays are "empty" until their first property/element. 289 // Objects and arrays are "empty" until their first property/element.
282 // At this position, they may either have an entry or a close-bracket. 290 // At this position, they may either have an entry or a close-bracket.
283 static const int EMPTY = 0; 291 static const int EMPTY = 0;
284 static const int NON_EMPTY = 16; 292 static const int NON_EMPTY = 16;
285 static const int EMPTY_MASK = 16; // Empty if zero. 293 static const int EMPTY_MASK = 16; // Empty if zero.
286 294
287 static const int VALUE_READ_BITS = NO_VALUES | NON_EMPTY; 295 // Actual states : Context | Is empty? | Next?
296 static const int STATE_INITIAL = TOP_LEVEL | EMPTY | ALLOW_VALUE;
297 static const int STATE_END = TOP_LEVEL | NON_EMPTY | NO_VALUES;
288 298
289 // Actual states. 299 static const int STATE_ARRAY_EMPTY = INSIDE_ARRAY | EMPTY | ALLOW_VALUE;
290 static const int STATE_INITIAL = EMPTY | ALLOW_VALUE; 300 static const int STATE_ARRAY_VALUE = INSIDE_ARRAY | NON_EMPTY | NO_VALUES;
291 static const int STATE_END = NON_EMPTY | NO_VALUES; 301 static const int STATE_ARRAY_COMMA = INSIDE_ARRAY | NON_EMPTY | ALLOW_VALUE;
292 302
293 static const int STATE_ARRAY_EMPTY = INSIDE_ARRAY | EMPTY | ALLOW_VALUE; 303 static const int STATE_OBJECT_EMPTY = INSIDE_OBJECT | EMPTY | STRING_ONLY;
294 static const int STATE_ARRAY_VALUE = INSIDE_ARRAY | NON_EMPTY | NO_VALUES; 304 static const int STATE_OBJECT_KEY = INSIDE_OBJECT | NON_EMPTY | NO_VALUES;
295 static const int STATE_ARRAY_COMMA = INSIDE_ARRAY | NON_EMPTY | ALLOW_VALUE; 305 static const int STATE_OBJECT_COLON = AFTER_COLON | NON_EMPTY | ALLOW_VALUE;
306 static const int STATE_OBJECT_VALUE = AFTER_COLON | NON_EMPTY | NO_VALUES;
307 static const int STATE_OBJECT_COMMA = INSIDE_OBJECT | NON_EMPTY | STRING_ONLY;
296 308
297 static const int STATE_OBJECT_EMPTY = INSIDE_OBJECT | EMPTY | STRING_ONLY; 309 // Bits set in state after successfully reading a value.
298 static const int STATE_OBJECT_KEY = INSIDE_OBJECT | NON_EMPTY | NO_VALUES; 310 // This transitions the state to expect the next punctuation.
299 static const int STATE_OBJECT_COLON = AFTER_COLON | NON_EMPTY | ALLOW_VALUE; 311 static const int VALUE_READ_BITS = NON_EMPTY | NO_VALUES;
300 static const int STATE_OBJECT_VALUE = AFTER_COLON | NON_EMPTY | NO_VALUES;
301 static const int STATE_OBJECT_COMMA = INSIDE_OBJECT | NON_EMPTY | STRING_ONLY;
302 312
303 // Character code constants. 313 // Character code constants.
304 static const int BACKSPACE = 0x08; 314 static const int BACKSPACE = 0x08;
305 static const int TAB = 0x09; 315 static const int TAB = 0x09;
306 static const int NEWLINE = 0x0a; 316 static const int NEWLINE = 0x0a;
307 static const int CARRIAGE_RETURN = 0x0d; 317 static const int CARRIAGE_RETURN = 0x0d;
308 static const int FORM_FEED = 0x0c; 318 static const int FORM_FEED = 0x0c;
309 static const int SPACE = 0x20; 319 static const int SPACE = 0x20;
310 static const int QUOTE = 0x22; 320 static const int QUOTE = 0x22;
311 static const int PLUS = 0x2b; 321 static const int PLUS = 0x2b;
(...skipping 15 matching lines...) Expand all
327 static const int CHAR_l = 0x6c; 337 static const int CHAR_l = 0x6c;
328 static const int CHAR_n = 0x6e; 338 static const int CHAR_n = 0x6e;
329 static const int CHAR_r = 0x72; 339 static const int CHAR_r = 0x72;
330 static const int CHAR_s = 0x73; 340 static const int CHAR_s = 0x73;
331 static const int CHAR_t = 0x74; 341 static const int CHAR_t = 0x74;
332 static const int CHAR_u = 0x75; 342 static const int CHAR_u = 0x75;
333 static const int LBRACE = 0x7b; 343 static const int LBRACE = 0x7b;
334 static const int RBRACE = 0x7d; 344 static const int RBRACE = 0x7d;
335 345
336 // State of partial value at chunk split. 346 // State of partial value at chunk split.
337 static const int NO_PARTIAL = 0; 347 static const int NO_PARTIAL = 0;
338 static const int PARTIAL_STRING = 1; 348 static const int PARTIAL_STRING = 1;
339 static const int PARTIAL_NUMERAL = 2; 349 static const int PARTIAL_NUMERAL = 2;
340 static const int PARTIAL_KEYWORD = 3; 350 static const int PARTIAL_KEYWORD = 3;
341 static const int MASK_PARTIAL = 3; 351 static const int MASK_PARTIAL = 3;
342 352
343 // Partial states for numerals. Values can be |'ed with PARTIAL_NUMERAL. 353 // Partial states for numerals. Values can be |'ed with PARTIAL_NUMERAL.
344 static const int NUM_SIGN = 0; // After initial '-'. 354 static const int NUM_SIGN = 0; // After initial '-'.
345 static const int NUM_ZERO = 4; // After '0' as first digit. 355 static const int NUM_ZERO = 4; // After '0' as first digit.
346 static const int NUM_DIGIT = 8; // After digit, no '.' or 'e' seen. 356 static const int NUM_DIGIT = 8; // After digit, no '.' or 'e' seen.
347 static const int NUM_DOT = 12; // After '.'. 357 static const int NUM_DOT = 12; // After '.'.
348 static const int NUM_DOT_DIGIT = 16; // After a decimal digit (after '.'). 358 static const int NUM_DOT_DIGIT = 16; // After a decimal digit (after '.') .
349 static const int NUM_E = 20; // After 'e' or 'E'. 359 static const int NUM_E = 20; // After 'e' or 'E'.
350 static const int NUM_E_SIGN = 24; // After '-' or '+' after 'e' or 'E'. 360 static const int NUM_E_SIGN = 24; // After '-' or '+' after 'e' or 'E' .
351 static const int NUM_E_DIGIT = 28; // After exponent digit. 361 static const int NUM_E_DIGIT = 28; // After exponent digit.
352 static const int NUM_SUCCESS = 32; // Never stored as partial state. 362 static const int NUM_SUCCESS = 32; // Never stored as partial state.
353 363
354 // Partial states for strings. 364 // Partial states for strings.
355 static const int STR_PLAIN = 0; // Inside string, but not escape. 365 static const int STR_PLAIN = 0; // Inside string, but not escape.
356 static const int STR_ESCAPE = 4; // After '\'. 366 static const int STR_ESCAPE = 4; // After '\'.
357 static const int STR_U = 16; // After '\u' and 0-3 hex digits. 367 static const int STR_U = 16; // After '\u' and 0-3 hex digits.
358 static const int STR_U_COUNT_SHIFT = 2; // Hex digit count in bits 2-3. 368 static const int STR_U_COUNT_SHIFT = 2; // Hex digit count in bits 2-3.
359 static const int STR_U_VALUE_SHIFT = 5; // Hex digit value in bits 5+. 369 static const int STR_U_VALUE_SHIFT = 5; // Hex digit value in bits 5+.
360 370
361 // Partial states for keywords. 371 // Partial states for keywords.
362 static const int KWD_TYPE_MASK = 12; 372 static const int KWD_TYPE_MASK = 12;
363 static const int KWD_TYPE_SHIFT = 2; 373 static const int KWD_TYPE_SHIFT = 2;
364 static const int KWD_NULL = 0; // Prefix of "null" seen. 374 static const int KWD_NULL = 0; // Prefix of "null" seen.
365 static const int KWD_TRUE = 4; // Prefix of "true" seen. 375 static const int KWD_TRUE = 4; // Prefix of "true" seen.
366 static const int KWD_FALSE = 8; // Prefix of "false" seen. 376 static const int KWD_FALSE = 8; // Prefix of "false" seen.
367 static const int KWD_COUNT_SHIFT = 4; // Prefix length in bits 4+. 377 static const int KWD_COUNT_SHIFT = 4; // Prefix length in bits 4+.
368 378
369 // Mask used to mask off two lower bits. 379 // Mask used to mask off two lower bits.
370 static const int TWO_BIT_MASK = 3; 380 static const int TWO_BIT_MASK = 3;
371 381
372 final _JsonListener listener; 382 final _JsonListener listener;
373 383
374 // The current parsing state. 384 // The current parsing state.
375 int state = STATE_INITIAL; 385 int state = STATE_INITIAL;
376 List<int> states = <int>[]; 386 List<int> states = <int>[];
377 387
378 /** 388 /**
379 * Stores tokenizer state between chunks. 389 * Stores tokenizer state between chunks.
380 * 390 *
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
507 * In practive, [index] will be no smaller than the `start` argument passed 517 * In practive, [index] will be no smaller than the `start` argument passed
508 * to [parse]. 518 * to [parse].
509 */ 519 */
510 int getChar(int index); 520 int getChar(int index);
511 521
512 /** 522 /**
513 * Copy ASCII characters from start to end of chunk into a list. 523 * Copy ASCII characters from start to end of chunk into a list.
514 * 524 *
515 * Used for number buffer (always copies ASCII, so encoding is not important). 525 * Used for number buffer (always copies ASCII, so encoding is not important).
516 */ 526 */
517 void copyCharsToList(int start, int end, List<int> target); 527 void copyCharsToList(int start, int end, List<int> target, int offset);
518 528
519 /** 529 /**
520 * Build a string using input code units. 530 * Build a string using input code units.
521 * 531 *
522 * Creates a string buffer and enables adding characters and slices 532 * Creates a string buffer and enables adding characters and slices
523 * to that buffer. 533 * to that buffer.
524 * The buffer is stored in the [buffer] field. If the string is unterminated, 534 * The buffer is stored in the [buffer] field. If the string is unterminated,
525 * the same buffer is used to continue parsing in the next chunk. 535 * the same buffer is used to continue parsing in the next chunk.
526 */ 536 */
527 void beginString(); 537 void beginString();
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
585 * Create a _NumberBuffer containing the digits from [start] to [chunkEnd]. 595 * Create a _NumberBuffer containing the digits from [start] to [chunkEnd].
586 * 596 *
587 * This creates a number buffer and initializes it with the part of the 597 * This creates a number buffer and initializes it with the part of the
588 * number literal ending the current chunk 598 * number literal ending the current chunk
589 */ 599 */
590 void createNumberBuffer(int start) { 600 void createNumberBuffer(int start) {
591 assert(start >= 0); 601 assert(start >= 0);
592 assert(start < chunkEnd); 602 assert(start < chunkEnd);
593 int length = chunkEnd - start; 603 int length = chunkEnd - start;
594 var buffer = new _NumberBuffer(length); 604 var buffer = new _NumberBuffer(length);
595 copyCharsToList(start, chunkEnd, buffer.list); 605 copyCharsToList(start, chunkEnd, buffer.list, 0);
596 buffer.length = length; 606 buffer.length = length;
597 return buffer; 607 return buffer;
598 } 608 }
599 609
600 /** 610 /**
601 * Continues parsing a partial value. 611 * Continues parsing a partial value.
602 */ 612 */
603 int parsePartial(int position) { 613 int parsePartial(int position) {
604 if (position == chunkEnd) return position; 614 if (position == chunkEnd) return position;
605 int partialState = this.partialState; 615 int partialState = this.partialState;
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after
793 */ 803 */
794 void parse(int position) { 804 void parse(int position) {
795 int length = chunkEnd; 805 int length = chunkEnd;
796 if (partialState != NO_PARTIAL) { 806 if (partialState != NO_PARTIAL) {
797 position = parsePartial(position); 807 position = parsePartial(position);
798 if (position == length) return; 808 if (position == length) return;
799 } 809 }
800 int state = this.state; 810 int state = this.state;
801 while (position < length) { 811 while (position < length) {
802 int char = getChar(position); 812 int char = getChar(position);
803 if (char == null) {
804 print("[[[$chunk]]] - $position - ${chunk.runtimeType}");
805 }
806 switch (char) { 813 switch (char) {
807 case SPACE: 814 case SPACE:
808 case CARRIAGE_RETURN: 815 case CARRIAGE_RETURN:
809 case NEWLINE: 816 case NEWLINE:
810 case TAB: 817 case TAB:
811 position++; 818 position++;
812 break; 819 break;
813 case QUOTE: 820 case QUOTE:
814 if ((state & ALLOW_STRING_MASK) != 0) return fail(position); 821 if ((state & ALLOW_STRING_MASK) != 0) return fail(position);
815 state |= VALUE_READ_BITS; 822 state |= VALUE_READ_BITS;
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
894 position = parseNumber(char, position); 901 position = parseNumber(char, position);
895 break; 902 break;
896 } 903 }
897 } 904 }
898 this.state = state; 905 this.state = state;
899 } 906 }
900 907
901 /** 908 /**
902 * Parses a "true" literal starting at [position]. 909 * Parses a "true" literal starting at [position].
903 * 910 *
904 * [:source[position]:] must be "t". 911 * The character `source[position]` must be "t".
905 */ 912 */
906 int parseTrue(int position) { 913 int parseTrue(int position) {
907 assert(getChar(position) == CHAR_t); 914 assert(getChar(position) == CHAR_t);
908 if (chunkEnd < position + 4) { 915 if (chunkEnd < position + 4) {
909 return parseKeywordPrefix(position, "true", KWD_TRUE); 916 return parseKeywordPrefix(position, "true", KWD_TRUE);
910 } 917 }
911 if (getChar(position + 1) != CHAR_r || 918 if (getChar(position + 1) != CHAR_r ||
912 getChar(position + 2) != CHAR_u || 919 getChar(position + 2) != CHAR_u ||
913 getChar(position + 3) != CHAR_e) { 920 getChar(position + 3) != CHAR_e) {
914 return fail(position); 921 return fail(position);
915 } 922 }
916 listener.handleBool(true); 923 listener.handleBool(true);
917 return position + 4; 924 return position + 4;
918 } 925 }
919 926
920 /** 927 /**
921 * Parses a "false" literal starting at [position]. 928 * Parses a "false" literal starting at [position].
922 * 929 *
923 * [:source[position]:] must be "f". 930 * The character `source[position]` must be "f".
924 */ 931 */
925 int parseFalse(int position) { 932 int parseFalse(int position) {
926 assert(getChar(position) == CHAR_f); 933 assert(getChar(position) == CHAR_f);
927 if (chunkEnd < position + 5) { 934 if (chunkEnd < position + 5) {
928 return parseKeywordPrefix(position, "false", KWD_FALSE); 935 return parseKeywordPrefix(position, "false", KWD_FALSE);
929 } 936 }
930 if (getChar(position + 1) != CHAR_a || 937 if (getChar(position + 1) != CHAR_a ||
931 getChar(position + 2) != CHAR_l || 938 getChar(position + 2) != CHAR_l ||
932 getChar(position + 3) != CHAR_s || 939 getChar(position + 3) != CHAR_s ||
933 getChar(position + 4) != CHAR_e) { 940 getChar(position + 4) != CHAR_e) {
934 return fail(position); 941 return fail(position);
935 } 942 }
936 listener.handleBool(false); 943 listener.handleBool(false);
937 return position + 5; 944 return position + 5;
938 } 945 }
939 946
940 /** 947 /**
941 * Parses a "null" literal starting at [position]. 948 * Parses a "null" literal starting at [position].
942 * 949 *
943 * [:source[position]:] must be "n". 950 * The character `source[position]` must be "n".
944 */ 951 */
945 int parseNull(int position) { 952 int parseNull(int position) {
946 assert(getChar(position) == CHAR_n); 953 assert(getChar(position) == CHAR_n);
947 if (chunkEnd < position + 4) { 954 if (chunkEnd < position + 4) {
948 return parseKeywordPrefix(position, "null", KWD_NULL); 955 return parseKeywordPrefix(position, "null", KWD_NULL);
949 } 956 }
950 if (getChar(position + 1) != CHAR_u || 957 if (getChar(position + 1) != CHAR_u ||
951 getChar(position + 2) != CHAR_l || 958 getChar(position + 2) != CHAR_l ||
952 getChar(position + 3) != CHAR_l) { 959 getChar(position + 3) != CHAR_l) {
953 return fail(position); 960 return fail(position);
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
993 beginString(); 1000 beginString();
994 int sliceEnd = position - 1; 1001 int sliceEnd = position - 1;
995 if (start < sliceEnd) addSliceToString(start, sliceEnd); 1002 if (start < sliceEnd) addSliceToString(start, sliceEnd);
996 return parseStringToBuffer(sliceEnd); 1003 return parseStringToBuffer(sliceEnd);
997 } 1004 }
998 if (char == QUOTE) { 1005 if (char == QUOTE) {
999 listener.handleString(getString(start, position - 1, bits)); 1006 listener.handleString(getString(start, position - 1, bits));
1000 return position; 1007 return position;
1001 } 1008 }
1002 if (char < SPACE) { 1009 if (char < SPACE) {
1003 fail(position - 1, "Control character in string"); 1010 return fail(position - 1, "Control character in string");
1004 } 1011 }
1005 } 1012 }
1006 beginString(); 1013 beginString();
1007 if (start < end) addSliceToString(start, end); 1014 if (start < end) addSliceToString(start, end);
1008 return chunkString(STR_PLAIN); 1015 return chunkString(STR_PLAIN);
1009 } 1016 }
1010 1017
1011 /** 1018 /**
1012 * Sets up a partial string state. 1019 * Sets up a partial string state.
1013 * 1020 *
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
1052 while (true) { 1059 while (true) {
1053 if (position == end) { 1060 if (position == end) {
1054 if (position > start) { 1061 if (position > start) {
1055 addSliceToString(start, position); 1062 addSliceToString(start, position);
1056 } 1063 }
1057 return chunkString(STR_PLAIN); 1064 return chunkString(STR_PLAIN);
1058 } 1065 }
1059 int char = getChar(position++); 1066 int char = getChar(position++);
1060 if (char > BACKSLASH) continue; 1067 if (char > BACKSLASH) continue;
1061 if (char < SPACE) { 1068 if (char < SPACE) {
1062 fail(position - 1); // Control character in string. 1069 return fail(position - 1); // Control character in string.
1063 return;
1064 } 1070 }
1065 if (char == QUOTE) { 1071 if (char == QUOTE) {
1066 int quotePosition = position - 1; 1072 int quotePosition = position - 1;
1067 if (quotePosition > start) { 1073 if (quotePosition > start) {
1068 addSliceToString(start, quotePosition); 1074 addSliceToString(start, quotePosition);
1069 } 1075 }
1070 listener.handleString(endString()); 1076 listener.handleString(endString());
1071 return position; 1077 return position;
1072 } 1078 }
1073 if (char != BACKSLASH) { 1079 if (char != BACKSLASH) {
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
1164 int end = chunkEnd; 1170 int end = chunkEnd;
1165 addNumberChunk(buffer, start, end, _NumberBuffer.kDefaultOverhead); 1171 addNumberChunk(buffer, start, end, _NumberBuffer.kDefaultOverhead);
1166 this.buffer = buffer; 1172 this.buffer = buffer;
1167 this.partialState = PARTIAL_NUMERAL | state; 1173 this.partialState = PARTIAL_NUMERAL | state;
1168 return end; 1174 return end;
1169 } 1175 }
1170 1176
1171 int finishChunkNumber(int state, int start, int end, _NumberBuffer buffer) { 1177 int finishChunkNumber(int state, int start, int end, _NumberBuffer buffer) {
1172 if (state == NUM_ZERO) { 1178 if (state == NUM_ZERO) {
1173 listener.handleNumber(0); 1179 listener.handleNumber(0);
1174 return; 1180 return end;
1175 } 1181 }
1176 if (end > start) { 1182 if (end > start) {
1177 addNumberChunk(buffer, start, end, 0); 1183 addNumberChunk(buffer, start, end, 0);
1178 } 1184 }
1179 if (state == NUM_DIGIT) { 1185 if (state == NUM_DIGIT) {
1180 listener.handleNumber(buffer.parseInt()); 1186 listener.handleNumber(buffer.parseInt());
1181 } else if (state == NUM_DOT_DIGIT || state == NUM_E_DIGIT) { 1187 } else if (state == NUM_DOT_DIGIT || state == NUM_E_DIGIT) {
1182 listener.handleNumber(buffer.parseDouble()); 1188 listener.handleNumber(buffer.parseDouble());
1183 } else { 1189 } else {
1184 fail(chunkEnd, "Unterminated number literal"); 1190 fail(chunkEnd, "Unterminated number literal");
1185 } 1191 }
1186 return end; 1192 return end;
1187 } 1193 }
1188 1194
1189 int parseNumber(int char, int position) { 1195 int parseNumber(int char, int position) {
1190 // Also called on any unexpected character. 1196 // Also called on any unexpected character.
1191 // Format: 1197 // Format:
1192 // '-'?('0'|[1-9][0-9]*)('.'[0-9]+)?([eE][+-]?[0-9]+)? 1198 // '-'?('0'|[1-9][0-9]*)('.'[0-9]+)?([eE][+-]?[0-9]+)?
1193 int start = position; 1199 int start = position;
1194 int length = chunkEnd; 1200 int length = chunkEnd;
1195 // Collects an int value while parsing. Used for both an integer literal, 1201 // Collects an int value while parsing. Used for both an integer literal,
1196 // an the exponent part of a double literal. 1202 // an the exponent part of a double literal.
1197 int intValue = 0; 1203 int intValue = 0;
1198 double doubleValue = 0.0; // Collect double value while parsing. 1204 double doubleValue = 0.0; // Collect double value while parsing.
1199 int sign = 1; 1205 int sign = 1;
1200 bool isDouble = false; 1206 bool isDouble = false;
1201 // Break this block when the end of the number literal is reached. 1207 // Break this block when the end of the number literal is reached.
1202 // At that time, position points to the next character, and isDouble 1208 // At that time, position points to the next character, and isDouble
1203 // is set if the literal contains a decimal point or an exponential. 1209 // is set if the literal contains a decimal point or an exponential.
1204 parsing: { 1210 if (char == MINUS) {
1205 if (char == MINUS) { 1211 sign = -1;
1206 sign = -1; 1212 position++;
1213 if (position == length) return beginChunkNumber(NUM_SIGN, start);
1214 char = getChar(position);
1215 }
1216 int digit = char ^ CHAR_0;
1217 if (digit > 9) {
1218 if (sign < 0) {
1219 fail(position, "Missing expected digit");
1220 } else {
1221 // If it doesn't even start out as a numeral.
1222 fail(position, "Unexpected character");
1223 }
1224 }
1225 if (digit == 0) {
1226 position++;
1227 if (position == length) return beginChunkNumber(NUM_ZERO, start);
1228 char = getChar(position);
1229 digit = char ^ CHAR_0;
1230 // If starting with zero, next character must not be digit.
1231 if (digit <= 9) fail(position);
1232 } else {
1233 do {
1234 intValue = 10 * intValue + digit;
1207 position++; 1235 position++;
1208 if (position == length) return beginChunkNumber(NUM_SIGN, start); 1236 if (position == length) return beginChunkNumber(NUM_DIGIT, start);
1237 char = getChar(position);
1238 digit = char ^ CHAR_0;
1239 } while (digit <= 9);
1240 }
1241 if (char == DECIMALPOINT) {
1242 isDouble = true;
1243 doubleValue = intValue.toDouble();
1244 intValue = 0;
1245 position++;
1246 if (position == length) return beginChunkNumber(NUM_DOT, start);
1247 char = getChar(position);
1248 digit = char ^ CHAR_0;
1249 if (digit > 9) fail(position);
1250 do {
1251 doubleValue = 10.0 * doubleValue + digit;
1252 intValue -= 1;
1253 position++;
1254 if (position == length) return beginChunkNumber(NUM_DOT_DIGIT, start);
1255 char = getChar(position);
1256 digit = char ^ CHAR_0;
1257 } while (digit <= 9);
1258 }
1259 if ((char | 0x20) == CHAR_e) {
1260 if (!isDouble) {
1261 doubleValue = intValue.toDouble();
1262 intValue = 0;
1263 isDouble = true;
1264 }
1265 position++;
1266 if (position == length) return beginChunkNumber(NUM_E, start);
1267 char = getChar(position);
1268 int expSign = 1;
1269 int exponent = 0;
1270 if (char == PLUS || char == MINUS) {
1271 expSign = 0x2C - char; // -1 for MINUS, +1 for PLUS
1272 position++;
1273 if (position == length) return beginChunkNumber(NUM_E_SIGN, start);
1209 char = getChar(position); 1274 char = getChar(position);
1210 } 1275 }
1211 int digit = char ^ CHAR_0; 1276 digit = char ^ CHAR_0;
1212 if (digit > 9) { 1277 if (digit > 9) {
1213 if (sign < 0) { 1278 fail(position, "Missing expected digit");
1214 fail(position, "Missing expected digit");
1215 } else {
1216 // If it doesn't even start out as a numeral.
1217 fail(position, "Unexpected character");
1218 }
1219 } 1279 }
1220 if (digit == 0) { 1280 do {
1281 exponent = 10 * exponent + digit;
1221 position++; 1282 position++;
1222 if (position == length) return beginChunkNumber(NUM_ZERO, start); 1283 if (position == length) return beginChunkNumber(NUM_E_DIGIT, start);
1223 char = getChar(position); 1284 char = getChar(position);
1224 digit = char ^ CHAR_0; 1285 digit = char ^ CHAR_0;
1225 // If starting with zero, next character must not be digit. 1286 } while (digit <= 9);
1226 if (digit <= 9) fail(position); 1287 intValue += expSign * exponent;
1227 } else {
1228 do {
1229 intValue = 10 * intValue + digit;
1230 position++;
1231 if (position == length) return beginChunkNumber(NUM_DIGIT, start);
1232 char = getChar(position);
1233 digit = char ^ CHAR_0;
1234 } while (digit <= 9);
1235 }
1236 if (char == DECIMALPOINT) {
1237 isDouble = true;
1238 doubleValue = intValue.toDouble();
1239 intValue = 0;
1240 position++;
1241 if (position == length) return beginChunkNumber(NUM_DOT, start);
1242 char = getChar(position);
1243 digit = char ^ CHAR_0;
1244 if (digit > 9) fail(position);
1245 do {
1246 doubleValue = 10.0 * doubleValue + digit;
1247 intValue -= 1;
1248 position++;
1249 if (position == length) return beginChunkNumber(NUM_DOT_DIGIT, start);
1250 char = getChar(position);
1251 digit = char ^ CHAR_0;
1252 } while (digit <= 9);
1253 }
1254 if ((char | 0x20) == CHAR_e) {
1255 if (!isDouble) {
1256 doubleValue = intValue.toDouble();
1257 intValue = 0;
1258 isDouble = true;
1259 }
1260 position++;
1261 if (position == length) return beginChunkNumber(NUM_E, start);
1262 char = getChar(position);
1263 int expSign = 1;
1264 int exponent = 0;
1265 if (char == PLUS || char == MINUS) {
1266 expSign = 0x2C - char; // -1 for MINUS, +1 for PLUS
1267 position++;
1268 if (position == length) return beginChunkNumber(NUM_E_SIGN, start);
1269 char = getChar(position);
1270 }
1271 digit = char ^ CHAR_0;
1272 if (digit > 9) {
1273 fail(position, "Missing expected digit");
1274 }
1275 do {
1276 exponent = 10 * exponent + digit;
1277 position++;
1278 if (position == length) return beginChunkNumber(NUM_E_DIGIT, start);
1279 char = getChar(position);
1280 digit = char ^ CHAR_0;
1281 } while (digit <= 9);
1282 intValue += expSign * exponent;
1283 }
1284 } 1288 }
1285 if (!isDouble) { 1289 if (!isDouble) {
1286 listener.handleNumber(sign * intValue); 1290 listener.handleNumber(sign * intValue);
1287 return position; 1291 return position;
1288 } 1292 }
1289 // Double values at or above this value (2 ** 53) may have lost precission. 1293 // Double values at or above this value (2 ** 53) may have lost precission.
1290 // Only trust results that are below this value. 1294 // Only trust results that are below this value.
1291 const double maxExactDouble = 9007199254740992.0; 1295 const double maxExactDouble = 9007199254740992.0;
1292 if (doubleValue < maxExactDouble) { 1296 if (doubleValue < maxExactDouble) {
1293 int exponent = intValue; 1297 int exponent = intValue;
(...skipping 13 matching lines...) Expand all
1307 } 1311 }
1308 } 1312 }
1309 } 1313 }
1310 // If the value is outside the range +/-maxExactDouble or 1314 // If the value is outside the range +/-maxExactDouble or
1311 // exponent is outside the range +/-22, then we can't trust simple double 1315 // exponent is outside the range +/-22, then we can't trust simple double
1312 // arithmetic to get the exact result, so we use the system double parsing. 1316 // arithmetic to get the exact result, so we use the system double parsing.
1313 listener.handleNumber(parseDouble(start, position)); 1317 listener.handleNumber(parseDouble(start, position));
1314 return position; 1318 return position;
1315 } 1319 }
1316 1320
1317 int fail(int position, [String message]) { 1321 fail(int position, [String message]) {
1318 if (message == null) { 1322 if (message == null) {
1319 message = "Unexpected character"; 1323 message = "Unexpected character";
1320 if (position == chunkEnd) message = "Unexpected end of input"; 1324 if (position == chunkEnd) message = "Unexpected end of input";
1321 } 1325 }
1322 throw new FormatException(message, chunk, position); 1326 throw new FormatException(message, chunk, position);
1323 } 1327 }
1324 } 1328 }
1325 1329
1326 /** 1330 /**
1327 * Chunked JSON parser that parses [String] chunks. 1331 * Chunked JSON parser that parses [String] chunks.
(...skipping 433 matching lines...) Expand 10 before | Expand all | Expand 10 after
1761 _parser.parse(start); 1765 _parser.parse(start);
1762 } 1766 }
1763 1767
1764 void close() { 1768 void close() {
1765 _parser.close(); 1769 _parser.close();
1766 var decoded = _parser.result; 1770 var decoded = _parser.result;
1767 _sink.add(decoded); 1771 _sink.add(decoded);
1768 _sink.close(); 1772 _sink.close();
1769 } 1773 }
1770 } 1774 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698