private JsonToken scanNumber()

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

    }