in grails-data-mongodb/bson/src/main/groovy/org/grails/datastore/bson/json/JsonScanner.java [223:437]
private JsonToken scanNumber(final char firstChar) throws IOException {
int c = firstChar;
JsonScanner.NumberState state;
StringBuilder numberBuilder = new StringBuilder();
numberBuilder.append(firstChar);
switch (c) {
case '-':
state = JsonScanner.NumberState.SAW_LEADING_MINUS;
break;
case '0':
state = JsonScanner.NumberState.SAW_LEADING_ZERO;
break;
default:
state = JsonScanner.NumberState.SAW_INTEGER_DIGITS;
break;
}
JsonTokenType type = JsonTokenType.INT64;
while (true) {
c = readCharacter();
switch (state) {
case SAW_LEADING_MINUS:
switch (c) {
case '0':
numberBuilder.append((char)c);
state = JsonScanner.NumberState.SAW_LEADING_ZERO;
break;
case 'I':
numberBuilder.append((char)c);
state = JsonScanner.NumberState.SAW_MINUS_I;
break;
default:
numberBuilder.append((char)c);
if (Character.isDigit(c)) {
state = JsonScanner.NumberState.SAW_INTEGER_DIGITS;
} else {
state = JsonScanner.NumberState.INVALID;
}
break;
}
break;
case SAW_LEADING_ZERO:
case SAW_INTEGER_DIGITS:
switch (c) {
case '.':
numberBuilder.append((char)c);
state = JsonScanner.NumberState.SAW_DECIMAL_POINT;
break;
case 'e':
case 'E':
numberBuilder.append((char)c);
state = JsonScanner.NumberState.SAW_EXPONENT_LETTER;
break;
case JsonToken.COMMA:
case JsonToken.CLOSE_BRACE:
case JsonToken.CLOSE_BRACKET:
case JsonToken.CLOSE_PARENS:
case -1:
state = JsonScanner.NumberState.DONE;
break;
default:
if (Character.isDigit(c)) {
numberBuilder.append((char)c);
state = JsonScanner.NumberState.SAW_INTEGER_DIGITS;
} else if (Character.isWhitespace(c)) {
state = JsonScanner.NumberState.DONE;
} else {
state = JsonScanner.NumberState.INVALID;
}
break;
}
break;
case SAW_DECIMAL_POINT:
type = JsonTokenType.DOUBLE;
if (Character.isDigit(c)) {
numberBuilder.append((char)c);
state = JsonScanner.NumberState.SAW_FRACTION_DIGITS;
} else {
state = JsonScanner.NumberState.INVALID;
}
break;
case SAW_FRACTION_DIGITS:
switch (c) {
case 'e':
case 'E':
numberBuilder.append((char)c);
state = JsonScanner.NumberState.SAW_EXPONENT_LETTER;
break;
case JsonToken.COMMA:
case JsonToken.CLOSE_BRACE:
case JsonToken.CLOSE_BRACKET:
case JsonToken.CLOSE_PARENS:
case -1:
state = JsonScanner.NumberState.DONE;
break;
default:
if (Character.isDigit(c)) {
numberBuilder.append((char)c);
state = JsonScanner.NumberState.SAW_FRACTION_DIGITS;
} else if (Character.isWhitespace(c)) {
state = JsonScanner.NumberState.DONE;
} else {
state = JsonScanner.NumberState.INVALID;
}
break;
}
break;
case SAW_EXPONENT_LETTER:
type = JsonTokenType.DOUBLE;
switch (c) {
case '+':
case '-':
numberBuilder.append((char)c);
state = JsonScanner.NumberState.SAW_EXPONENT_SIGN;
break;
default:
if (Character.isDigit(c)) {
numberBuilder.append((char)c);
state = JsonScanner.NumberState.SAW_EXPONENT_DIGITS;
} else {
state = JsonScanner.NumberState.INVALID;
}
break;
}
break;
case SAW_EXPONENT_SIGN:
if (Character.isDigit(c)) {
numberBuilder.append((char)c);
state = JsonScanner.NumberState.SAW_EXPONENT_DIGITS;
} else {
state = JsonScanner.NumberState.INVALID;
}
break;
case SAW_EXPONENT_DIGITS:
switch (c) {
case JsonToken.COMMA:
case JsonToken.CLOSE_BRACE:
case JsonToken.CLOSE_BRACKET:
case JsonToken.CLOSE_PARENS:
state = JsonScanner.NumberState.DONE;
break;
default:
if (Character.isDigit(c)) {
numberBuilder.append((char)c);
state = JsonScanner.NumberState.SAW_EXPONENT_DIGITS;
} else if (Character.isWhitespace(c)) {
state = JsonScanner.NumberState.DONE;
} else {
state = JsonScanner.NumberState.INVALID;
}
break;
}
break;
case SAW_MINUS_I:
boolean sawMinusInfinity = true;
numberBuilder.append((char)c);
for (int i = 0; i < NFINITY.length; i++) {
if (c != NFINITY[i]) {
sawMinusInfinity = false;
break;
}
c = readCharacter();
numberBuilder.append((char)c);
}
if (sawMinusInfinity) {
type = JsonTokenType.DOUBLE;
switch (c) {
case JsonToken.COMMA:
case JsonToken.CLOSE_BRACE:
case JsonToken.CLOSE_BRACKET:
case JsonToken.CLOSE_PARENS:
case -1:
state = JsonScanner.NumberState.DONE;
break;
default:
if (Character.isWhitespace(c)) {
state = JsonScanner.NumberState.DONE;
} else {
state = JsonScanner.NumberState.INVALID;
}
break;
}
} else {
state = JsonScanner.NumberState.INVALID;
}
break;
default:
}
switch (state) {
case INVALID:
throw new JsonParseException("Invalid JSON number");
case DONE:
reader.unread(c);
if (type == JsonTokenType.DOUBLE) {
return new JsonToken(JsonTokenType.DOUBLE, Double.parseDouble(numberBuilder.toString()));
} else {
long value = Long.parseLong(numberBuilder.toString());
if (value < Integer.MIN_VALUE || value > Integer.MAX_VALUE) {
return new JsonToken(JsonTokenType.INT64, value);
} else {
return new JsonToken(JsonTokenType.INT32, (int) value);
}
}
default:
}
}
}