private Object fetchNumberLike()

in freemarker-core/src/main/java/freemarker/core/_ObjectBuilderSettingEvaluator.java [371:479]


    private Object fetchNumberLike(boolean optional, boolean resultCoerced)
            throws _ObjectBuilderSettingEvaluationException {
        int startPos = pos;
        boolean isVersion = false;
        boolean hasDot = false;
        seekTokenEnd: while (true) {
            if (pos == src.length()) {
                break seekTokenEnd;
            }
            char c = src.charAt(pos);
            if (c == '.') {
                if (hasDot) {
                    // More than one dot
                    isVersion = true;
                } else {
                    hasDot = true;
                }
            } else if (!(isASCIIDigit(c) || c == '-')) {
                break seekTokenEnd;
            }
            pos++;
        }
        
        if (startPos == pos) {
            if (optional) {
                return VOID;
            } else {
                throw new _ObjectBuilderSettingEvaluationException("number-like", src, pos);
            }
        }
        
        String numStr = src.substring(startPos, pos);
        if (isVersion) {
            try {
                return new Version(numStr);
            } catch (IllegalArgumentException e) {
                throw new _ObjectBuilderSettingEvaluationException("Malformed version number: " + numStr, e);
            }
        } else {
            // For example, in 1.0f, numStr is "1.0", and typePostfix is "f".
            String typePostfix = null;
            seekTypePostfixEnd: while (true) {
                if (pos == src.length()) {
                    break seekTypePostfixEnd;
                }
                char c = src.charAt(pos);
                if (Character.isLetter(c)) {
                    if (typePostfix == null) {
                        typePostfix = String.valueOf(c);
                    } else {
                        typePostfix += c; 
                    }
                } else {
                    break seekTypePostfixEnd;
                }
                pos++;
            }
            
            try {
                if (numStr.endsWith(".")) {
                    throw new NumberFormatException("A number can't end with a dot");
                }
                if (numStr.startsWith(".") || numStr.startsWith("-.")  || numStr.startsWith("+.")) {
                    throw new NumberFormatException("A number can't start with a dot");
                }

                if (typePostfix == null) {
                    // Auto-detect type
                    if (numStr.indexOf('.') == -1) {
                        BigInteger biNum = new BigInteger(numStr);
                        final int bitLength = biNum.bitLength();  // Doesn't include sign bit
                        if (bitLength <= 31) {
                            return Integer.valueOf(biNum.intValue());
                        } else if (bitLength <= 63) {
                            return Long.valueOf(biNum.longValue());
                        } else {
                            return biNum;
                        }
                    } else {
                        if (resultCoerced) {
                            // The FTL way (BigDecimal is lossless, and it will be coerced to the target type later):
                            return new BigDecimal(numStr);
                        } else {
                            // The Java way (lossy but familiar):
                            return Double.valueOf(numStr);
                        }
                    }
                } else { // Has explicitly specified type
                    if (typePostfix.equalsIgnoreCase("l")) {
                        return Long.valueOf(numStr);
                    } else if (typePostfix.equalsIgnoreCase("bi")) {
                        return new BigInteger(numStr);
                    } else if (typePostfix.equalsIgnoreCase("bd")) {
                        return new BigDecimal(numStr);
                    } else if (typePostfix.equalsIgnoreCase("d")) {
                        return Double.valueOf(numStr);
                    } else if (typePostfix.equalsIgnoreCase("f")) {
                        return Float.valueOf(numStr);
                    } else {
                        throw new _ObjectBuilderSettingEvaluationException(
                                "Unrecognized number type postfix: " + typePostfix);
                    }
                }
                
            } catch (NumberFormatException e) {
                throw new _ObjectBuilderSettingEvaluationException("Malformed number: " + numStr, e);
            }
        }
    }