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