OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 } |
OLD | NEW |