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

Unified 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/lib/convert_patch.dart
diff --git a/runtime/lib/convert_patch.dart b/runtime/lib/convert_patch.dart
index 7b143accb17ddee8097c2f7dbde0b119ab7d5446..6d839699f004004fe54fe5e588ddd31d6ea0d48a 100644
--- a/runtime/lib/convert_patch.dart
+++ b/runtime/lib/convert_patch.dart
@@ -31,7 +31,7 @@ patch class Utf8Decoder {
return super.fuse(next);
}
- // Allow intercepting of UTF8 decoding when builtin lists are passed.
+ // Allow intercepting of UTF-8 decoding when built-in lists are passed.
/* patch */
static String _convertIntercepted(
bool allowMalformed, List<int> codeUnits, int start, int end) {
@@ -77,6 +77,13 @@ abstract class _JsonListener {
void beginArray() {}
void arrayElement() {}
void endArray() {}
+
+ /**
+ * Read out the final result of parsing a JSON string.
+ *
+ * Must only be called when the entire input has been parsed.
+ */
+ get result;
}
/**
@@ -268,38 +275,41 @@ abstract class _ChunkedJsonParser {
// gets to the next state (not empty, doesn't allow a value).
// State building-block constants.
- static const int INSIDE_ARRAY = 1;
- static const int INSIDE_OBJECT = 2;
- static const int AFTER_COLON = 3; // Always inside object.
+ static const int TOP_LEVEL = 0;
+ static const int INSIDE_ARRAY = 1;
+ static const int INSIDE_OBJECT = 2;
+ static const int AFTER_COLON = 3; // Always inside object.
static const int ALLOW_STRING_MASK = 8; // Allowed if zero.
- static const int ALLOW_VALUE_MASK = 4; // Allowed if zero.
- static const int ALLOW_VALUE = 0;
- static const int STRING_ONLY = 4;
- static const int NO_VALUES = 12;
+ static const int ALLOW_VALUE_MASK = 4; // Allowed if zero.
+ static const int ALLOW_VALUE = 0;
+ static const int STRING_ONLY = 4;
+ static const int NO_VALUES = 12;
// Objects and arrays are "empty" until their first property/element.
// At this position, they may either have an entry or a close-bracket.
- static const int EMPTY = 0;
- static const int NON_EMPTY = 16;
- static const int EMPTY_MASK = 16; // Empty if zero.
+ static const int EMPTY = 0;
+ static const int NON_EMPTY = 16;
+ static const int EMPTY_MASK = 16; // Empty if zero.
- static const int VALUE_READ_BITS = NO_VALUES | NON_EMPTY;
+ // Actual states : Context | Is empty? | Next?
+ static const int STATE_INITIAL = TOP_LEVEL | EMPTY | ALLOW_VALUE;
+ static const int STATE_END = TOP_LEVEL | NON_EMPTY | NO_VALUES;
- // Actual states.
- static const int STATE_INITIAL = EMPTY | ALLOW_VALUE;
- static const int STATE_END = NON_EMPTY | NO_VALUES;
+ static const int STATE_ARRAY_EMPTY = INSIDE_ARRAY | EMPTY | ALLOW_VALUE;
+ static const int STATE_ARRAY_VALUE = INSIDE_ARRAY | NON_EMPTY | NO_VALUES;
+ static const int STATE_ARRAY_COMMA = INSIDE_ARRAY | NON_EMPTY | ALLOW_VALUE;
- static const int STATE_ARRAY_EMPTY = INSIDE_ARRAY | EMPTY | ALLOW_VALUE;
- static const int STATE_ARRAY_VALUE = INSIDE_ARRAY | NON_EMPTY | NO_VALUES;
- static const int STATE_ARRAY_COMMA = INSIDE_ARRAY | NON_EMPTY | ALLOW_VALUE;
-
- static const int STATE_OBJECT_EMPTY = INSIDE_OBJECT | EMPTY | STRING_ONLY;
+ static const int STATE_OBJECT_EMPTY = INSIDE_OBJECT | EMPTY | STRING_ONLY;
static const int STATE_OBJECT_KEY = INSIDE_OBJECT | NON_EMPTY | NO_VALUES;
- static const int STATE_OBJECT_COLON = AFTER_COLON | NON_EMPTY | ALLOW_VALUE;
- static const int STATE_OBJECT_VALUE = AFTER_COLON | NON_EMPTY | NO_VALUES;
+ static const int STATE_OBJECT_COLON = AFTER_COLON | NON_EMPTY | ALLOW_VALUE;
+ static const int STATE_OBJECT_VALUE = AFTER_COLON | NON_EMPTY | NO_VALUES;
static const int STATE_OBJECT_COMMA = INSIDE_OBJECT | NON_EMPTY | STRING_ONLY;
+ // Bits set in state after successfully reading a value.
+ // This transitions the state to expect the next punctuation.
+ static const int VALUE_READ_BITS = NON_EMPTY | NO_VALUES;
+
// Character code constants.
static const int BACKSPACE = 0x08;
static const int TAB = 0x09;
@@ -334,40 +344,40 @@ abstract class _ChunkedJsonParser {
static const int RBRACE = 0x7d;
// State of partial value at chunk split.
- static const int NO_PARTIAL = 0;
- static const int PARTIAL_STRING = 1;
- static const int PARTIAL_NUMERAL = 2;
- static const int PARTIAL_KEYWORD = 3;
- static const int MASK_PARTIAL = 3;
+ static const int NO_PARTIAL = 0;
+ static const int PARTIAL_STRING = 1;
+ static const int PARTIAL_NUMERAL = 2;
+ static const int PARTIAL_KEYWORD = 3;
+ static const int MASK_PARTIAL = 3;
// Partial states for numerals. Values can be |'ed with PARTIAL_NUMERAL.
- static const int NUM_SIGN = 0; // After initial '-'.
- static const int NUM_ZERO = 4; // After '0' as first digit.
- static const int NUM_DIGIT = 8; // After digit, no '.' or 'e' seen.
- static const int NUM_DOT = 12; // After '.'.
- static const int NUM_DOT_DIGIT = 16; // After a decimal digit (after '.').
- static const int NUM_E = 20; // After 'e' or 'E'.
- static const int NUM_E_SIGN = 24; // After '-' or '+' after 'e' or 'E'.
- static const int NUM_E_DIGIT = 28; // After exponent digit.
- static const int NUM_SUCCESS = 32; // Never stored as partial state.
+ static const int NUM_SIGN = 0; // After initial '-'.
+ static const int NUM_ZERO = 4; // After '0' as first digit.
+ static const int NUM_DIGIT = 8; // After digit, no '.' or 'e' seen.
+ static const int NUM_DOT = 12; // After '.'.
+ static const int NUM_DOT_DIGIT = 16; // After a decimal digit (after '.').
+ static const int NUM_E = 20; // After 'e' or 'E'.
+ static const int NUM_E_SIGN = 24; // After '-' or '+' after 'e' or 'E'.
+ static const int NUM_E_DIGIT = 28; // After exponent digit.
+ static const int NUM_SUCCESS = 32; // Never stored as partial state.
// Partial states for strings.
static const int STR_PLAIN = 0; // Inside string, but not escape.
static const int STR_ESCAPE = 4; // After '\'.
- static const int STR_U = 16; // After '\u' and 0-3 hex digits.
+ static const int STR_U = 16; // After '\u' and 0-3 hex digits.
static const int STR_U_COUNT_SHIFT = 2; // Hex digit count in bits 2-3.
static const int STR_U_VALUE_SHIFT = 5; // Hex digit value in bits 5+.
// Partial states for keywords.
static const int KWD_TYPE_MASK = 12;
- static const int KWD_TYPE_SHIFT = 2;
- static const int KWD_NULL = 0; // Prefix of "null" seen.
- static const int KWD_TRUE = 4; // Prefix of "true" seen.
- static const int KWD_FALSE = 8; // Prefix of "false" seen.
- static const int KWD_COUNT_SHIFT = 4; // Prefix length in bits 4+.
+ static const int KWD_TYPE_SHIFT = 2;
+ static const int KWD_NULL = 0; // Prefix of "null" seen.
+ static const int KWD_TRUE = 4; // Prefix of "true" seen.
+ static const int KWD_FALSE = 8; // Prefix of "false" seen.
+ static const int KWD_COUNT_SHIFT = 4; // Prefix length in bits 4+.
// Mask used to mask off two lower bits.
- static const int TWO_BIT_MASK = 3;
+ static const int TWO_BIT_MASK = 3;
final _JsonListener listener;
@@ -514,7 +524,7 @@ abstract class _ChunkedJsonParser {
*
* Used for number buffer (always copies ASCII, so encoding is not important).
*/
- void copyCharsToList(int start, int end, List<int> target);
+ void copyCharsToList(int start, int end, List<int> target, int offset);
/**
* Build a string using input code units.
@@ -592,7 +602,7 @@ abstract class _ChunkedJsonParser {
assert(start < chunkEnd);
int length = chunkEnd - start;
var buffer = new _NumberBuffer(length);
- copyCharsToList(start, chunkEnd, buffer.list);
+ copyCharsToList(start, chunkEnd, buffer.list, 0);
buffer.length = length;
return buffer;
}
@@ -800,9 +810,6 @@ abstract class _ChunkedJsonParser {
int state = this.state;
while (position < length) {
int char = getChar(position);
- if (char == null) {
- print("[[[$chunk]]] - $position - ${chunk.runtimeType}");
- }
switch (char) {
case SPACE:
case CARRIAGE_RETURN:
@@ -901,7 +908,7 @@ abstract class _ChunkedJsonParser {
/**
* Parses a "true" literal starting at [position].
*
- * [:source[position]:] must be "t".
+ * The character `source[position]` must be "t".
*/
int parseTrue(int position) {
assert(getChar(position) == CHAR_t);
@@ -920,7 +927,7 @@ abstract class _ChunkedJsonParser {
/**
* Parses a "false" literal starting at [position].
*
- * [:source[position]:] must be "f".
+ * The character `source[position]` must be "f".
*/
int parseFalse(int position) {
assert(getChar(position) == CHAR_f);
@@ -940,7 +947,7 @@ abstract class _ChunkedJsonParser {
/**
* Parses a "null" literal starting at [position].
*
- * [:source[position]:] must be "n".
+ * The character `source[position]` must be "n".
*/
int parseNull(int position) {
assert(getChar(position) == CHAR_n);
@@ -1000,7 +1007,7 @@ abstract class _ChunkedJsonParser {
return position;
}
if (char < SPACE) {
- fail(position - 1, "Control character in string");
+ return fail(position - 1, "Control character in string");
}
}
beginString();
@@ -1059,8 +1066,7 @@ abstract class _ChunkedJsonParser {
int char = getChar(position++);
if (char > BACKSLASH) continue;
if (char < SPACE) {
- fail(position - 1); // Control character in string.
- return;
+ return fail(position - 1); // Control character in string.
}
if (char == QUOTE) {
int quotePosition = position - 1;
@@ -1171,7 +1177,7 @@ abstract class _ChunkedJsonParser {
int finishChunkNumber(int state, int start, int end, _NumberBuffer buffer) {
if (state == NUM_ZERO) {
listener.handleNumber(0);
- return;
+ return end;
}
if (end > start) {
addNumberChunk(buffer, start, end, 0);
@@ -1201,86 +1207,84 @@ abstract class _ChunkedJsonParser {
// Break this block when the end of the number literal is reached.
// At that time, position points to the next character, and isDouble
// is set if the literal contains a decimal point or an exponential.
- parsing: {
- if (char == MINUS) {
- sign = -1;
+ if (char == MINUS) {
+ sign = -1;
+ position++;
+ if (position == length) return beginChunkNumber(NUM_SIGN, start);
+ char = getChar(position);
+ }
+ int digit = char ^ CHAR_0;
+ if (digit > 9) {
+ if (sign < 0) {
+ fail(position, "Missing expected digit");
+ } else {
+ // If it doesn't even start out as a numeral.
+ fail(position, "Unexpected character");
+ }
+ }
+ if (digit == 0) {
+ position++;
+ if (position == length) return beginChunkNumber(NUM_ZERO, start);
+ char = getChar(position);
+ digit = char ^ CHAR_0;
+ // If starting with zero, next character must not be digit.
+ if (digit <= 9) fail(position);
+ } else {
+ do {
+ intValue = 10 * intValue + digit;
position++;
- if (position == length) return beginChunkNumber(NUM_SIGN, start);
+ if (position == length) return beginChunkNumber(NUM_DIGIT, start);
char = getChar(position);
- }
- int digit = char ^ CHAR_0;
- if (digit > 9) {
- if (sign < 0) {
- fail(position, "Missing expected digit");
- } else {
- // If it doesn't even start out as a numeral.
- fail(position, "Unexpected character");
- }
- }
- if (digit == 0) {
+ digit = char ^ CHAR_0;
+ } while (digit <= 9);
+ }
+ if (char == DECIMALPOINT) {
+ isDouble = true;
+ doubleValue = intValue.toDouble();
+ intValue = 0;
+ position++;
+ if (position == length) return beginChunkNumber(NUM_DOT, start);
+ char = getChar(position);
+ digit = char ^ CHAR_0;
+ if (digit > 9) fail(position);
+ do {
+ doubleValue = 10.0 * doubleValue + digit;
+ intValue -= 1;
position++;
- if (position == length) return beginChunkNumber(NUM_ZERO, start);
+ if (position == length) return beginChunkNumber(NUM_DOT_DIGIT, start);
char = getChar(position);
digit = char ^ CHAR_0;
- // If starting with zero, next character must not be digit.
- if (digit <= 9) fail(position);
- } else {
- do {
- intValue = 10 * intValue + digit;
- position++;
- if (position == length) return beginChunkNumber(NUM_DIGIT, start);
- char = getChar(position);
- digit = char ^ CHAR_0;
- } while (digit <= 9);
- }
- if (char == DECIMALPOINT) {
- isDouble = true;
+ } while (digit <= 9);
+ }
+ if ((char | 0x20) == CHAR_e) {
+ if (!isDouble) {
doubleValue = intValue.toDouble();
intValue = 0;
+ isDouble = true;
+ }
+ position++;
+ if (position == length) return beginChunkNumber(NUM_E, start);
+ char = getChar(position);
+ int expSign = 1;
+ int exponent = 0;
+ if (char == PLUS || char == MINUS) {
+ expSign = 0x2C - char; // -1 for MINUS, +1 for PLUS
position++;
- if (position == length) return beginChunkNumber(NUM_DOT, start);
+ if (position == length) return beginChunkNumber(NUM_E_SIGN, start);
char = getChar(position);
- digit = char ^ CHAR_0;
- if (digit > 9) fail(position);
- do {
- doubleValue = 10.0 * doubleValue + digit;
- intValue -= 1;
- position++;
- if (position == length) return beginChunkNumber(NUM_DOT_DIGIT, start);
- char = getChar(position);
- digit = char ^ CHAR_0;
- } while (digit <= 9);
}
- if ((char | 0x20) == CHAR_e) {
- if (!isDouble) {
- doubleValue = intValue.toDouble();
- intValue = 0;
- isDouble = true;
- }
+ digit = char ^ CHAR_0;
+ if (digit > 9) {
+ fail(position, "Missing expected digit");
+ }
+ do {
+ exponent = 10 * exponent + digit;
position++;
- if (position == length) return beginChunkNumber(NUM_E, start);
+ if (position == length) return beginChunkNumber(NUM_E_DIGIT, start);
char = getChar(position);
- int expSign = 1;
- int exponent = 0;
- if (char == PLUS || char == MINUS) {
- expSign = 0x2C - char; // -1 for MINUS, +1 for PLUS
- position++;
- if (position == length) return beginChunkNumber(NUM_E_SIGN, start);
- char = getChar(position);
- }
digit = char ^ CHAR_0;
- if (digit > 9) {
- fail(position, "Missing expected digit");
- }
- do {
- exponent = 10 * exponent + digit;
- position++;
- if (position == length) return beginChunkNumber(NUM_E_DIGIT, start);
- char = getChar(position);
- digit = char ^ CHAR_0;
- } while (digit <= 9);
- intValue += expSign * exponent;
- }
+ } while (digit <= 9);
+ intValue += expSign * exponent;
}
if (!isDouble) {
listener.handleNumber(sign * intValue);
@@ -1314,7 +1318,7 @@ abstract class _ChunkedJsonParser {
return position;
}
- int fail(int position, [String message]) {
+ fail(int position, [String message]) {
if (message == null) {
message = "Unexpected character";
if (position == chunkEnd) message = "Unexpected end of input";
« 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