private TemplateNumberModel tryConsumeNumber()

in freemarker-core/src/main/java/freemarker/core/JSONParser.java [163:258]


    private TemplateNumberModel tryConsumeNumber() throws JSONParseException {
        if (p >= ln) {
            return null;
        }
        char c = src.charAt(p);
        boolean negative = c == '-';
        if (!(negative || isDigit(c) || c == '.')) {
            return null;
        }

        int startP = p;

        if (negative) {
            if (p + 1 >= ln) {
                throw newParseException("Expected a digit after \"-\", but reached end-of-file.");
            }
            char lookAheadC = src.charAt(p + 1);
            if (!(isDigit(lookAheadC) || lookAheadC == '.')) {
                return null;
            }
            p++; // Consume "-" only, not the digit
        }

        long longSum = 0;
        boolean firstDigit = true;
        consumeLongFittingHead: do {
            c = src.charAt(p);

            if (!isDigit(c)) {
                if (c == '.' && firstDigit) {
                    throw newParseException("JSON doesn't allow numbers starting with \".\".");
                }
                break consumeLongFittingHead;
            }

            int digit = c - '0';
            if (longSum == 0) {
                if (!firstDigit) {
                    throw newParseException("JSON doesn't allow superfluous leading 0-s.", p - 1);
                }

                longSum = !negative ? digit : -digit;
                p++;
            } else {
                long prevLongSum = longSum;
                longSum = longSum * 10 + (!negative ? digit : -digit);
                if (!negative && prevLongSum > longSum || negative && prevLongSum < longSum) {
                    // We had an overflow => Can't consume this digit as long-fitting
                    break consumeLongFittingHead;
                }
                p++;
            }
            firstDigit = false;
        } while (p < ln);

        if (p < ln && isBigDecimalFittingTailCharacter(c)) {
            char lastC = c;
            p++;

            consumeBigDecimalFittingTail: while (p < ln) {
                c = src.charAt(p);
                if (isBigDecimalFittingTailCharacter(c)) {
                    p++;
                } else if ((c == '+' || c == '-') && isE(lastC)) {
                    p++;
                } else {
                    break consumeBigDecimalFittingTail;
                }
                lastC = c;
            }

            String numStr = src.substring(startP, p);
            BigDecimal bd;
            try {
                bd = new BigDecimal(numStr);
            } catch (NumberFormatException e) {
                throw new JSONParseException("Malformed number: " + numStr, src, startP, e);
            }

            if (bd.compareTo(MIN_INT_AS_BIGDECIMAL) >= 0 && bd.compareTo(MAX_INT_AS_BIGDECIMAL) <= 0) {
                if (NumberUtil.isIntegerBigDecimal(bd)) {
                    return new SimpleNumber(bd.intValue());
                }
            } else if (bd.compareTo(MIN_LONG_AS_BIGDECIMAL) >= 0 && bd.compareTo(MAX_LONG_AS_BIGDECIMAL) <= 0) {
                if (NumberUtil.isIntegerBigDecimal(bd)) {
                    return new SimpleNumber(bd.longValue());
                }
            }
            return new SimpleNumber(bd);
        } else {
            return new SimpleNumber(
                    longSum <= Integer.MAX_VALUE && longSum >= Integer.MIN_VALUE
                            ? (Number) (int) longSum
                            : longSum);
        }
    }