001/*
002 * Anarres C Preprocessor
003 * Copyright (c) 2007-2015, Shevek
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
014 * or implied.  See the License for the specific language governing
015 * permissions and limitations under the License.
016 */
017package org.anarres.cpp;
018
019import java.math.BigDecimal;
020import java.math.BigInteger;
021import javax.annotation.CheckForNull;
022import javax.annotation.CheckForSigned;
023import javax.annotation.Nonnegative;
024import javax.annotation.Nonnull;
025
026public class NumericValue extends Number {
027
028    public static final int F_UNSIGNED = 1;
029    public static final int F_INT = 2;
030    public static final int F_LONG = 4;
031    public static final int F_LONGLONG = 8;
032    public static final int F_FLOAT = 16;
033    public static final int F_DOUBLE = 32;
034
035    public static final int FF_SIZE = F_INT | F_LONG | F_LONGLONG | F_FLOAT | F_DOUBLE;
036
037    private final int base;
038    private final String integer;
039    private String fraction;
040    private int expbase = 0;
041    private String exponent;
042    private int flags;
043
044    public NumericValue(@Nonnegative int base, @Nonnull String integer) {
045        this.base = base;
046        this.integer = integer;
047    }
048
049    @Nonnegative
050    public int getBase() {
051        return base;
052    }
053
054    @Nonnull
055    public String getIntegerPart() {
056        return integer;
057    }
058
059    @CheckForNull
060    public String getFractionalPart() {
061        return fraction;
062    }
063
064    /* pp */ void setFractionalPart(@Nonnull String fraction) {
065        this.fraction = fraction;
066    }
067
068    @CheckForSigned
069    public int getExponentBase() {
070        return expbase;
071    }
072
073    @CheckForNull
074    public String getExponent() {
075        return exponent;
076    }
077
078    /* pp */ void setExponent(@Nonnegative int expbase, @Nonnull String exponent) {
079        this.expbase = expbase;
080        this.exponent = exponent;
081    }
082
083    public int getFlags() {
084        return flags;
085    }
086
087    /* pp */ void setFlags(int flags) {
088        this.flags = flags;
089    }
090
091    /**
092     * So, it turns out that parsing arbitrary bases into arbitrary
093     * precision numbers is nontrivial, and this routine gets it wrong
094     * in many important cases.
095     */
096    @Nonnull
097    public BigDecimal toBigDecimal() {
098        int scale = 0;
099        String text = getIntegerPart();
100        String t_fraction = getFractionalPart();
101        if (t_fraction != null) {
102            text += getFractionalPart();
103            // XXX Wrong for anything but base 10.
104            scale += t_fraction.length();
105        }
106        String t_exponent = getExponent();
107        if (t_exponent != null)
108            scale -= Integer.parseInt(t_exponent);
109        BigInteger unscaled = new BigInteger(text, getBase());
110        return new BigDecimal(unscaled, scale);
111    }
112
113    // We could construct a heuristic for when an 'int' is large enough.
114    // private static final int S_MAXLEN_LONG = String.valueOf(Long.MAX_VALUE).length();
115    // private static final int S_MAXLEN_INT = String.valueOf(Integer.MAX_VALUE).length();
116
117    @Nonnull
118    public Number toJavaLangNumber() {
119        int flags = getFlags();
120        if ((flags & F_DOUBLE) != 0)
121            return doubleValue();
122        else if ((flags & F_FLOAT) != 0)
123            return floatValue();
124        else if ((flags & (F_LONG | F_LONGLONG)) != 0)
125            return longValue();
126        else if ((flags & F_INT) != 0)
127            return intValue();
128        else if (getFractionalPart() != null)
129            return doubleValue();       // .1 is a double in Java.
130        else if (getExponent() != null)
131            return doubleValue();
132        else {
133            // This is an attempt to avoid overflowing on over-long integers.
134            // However, now we just overflow on over-long longs.
135            // We should really use BigInteger.
136            long value = longValue();
137            if (value <= Integer.MAX_VALUE && value >= Integer.MIN_VALUE)
138                return (int) value;
139            return value;
140        }
141    }
142
143    private int exponentValue() {
144        return Integer.parseInt(exponent, 10);
145    }
146
147    @Override
148    public int intValue() {
149        // String.isEmpty() is since 1.6
150        int v = integer.length() == 0 ? 0 : Integer.parseInt(integer, base);
151        if (expbase == 2)
152            v = v << exponentValue();
153        else if (expbase != 0)
154            v = (int) (v * Math.pow(expbase, exponentValue()));
155        return v;
156    }
157
158    @Override
159    public long longValue() {
160        // String.isEmpty() is since 1.6
161        long v = integer.length() == 0 ? 0 : Long.parseLong(integer, base);
162        if (expbase == 2)
163            v = v << exponentValue();
164        else if (expbase != 0)
165            v = (long) (v * Math.pow(expbase, exponentValue()));
166        return v;
167    }
168
169    @Override
170    public float floatValue() {
171        if (getBase() != 10)
172            return longValue();
173        return Float.parseFloat(toString());
174    }
175
176    @Override
177    public double doubleValue() {
178        if (getBase() != 10)
179            return longValue();
180        return Double.parseDouble(toString());
181    }
182
183    private boolean appendFlags(StringBuilder buf, String suffix, int flag) {
184        if ((getFlags() & flag) != flag)
185            return false;
186        buf.append(suffix);
187        return true;
188    }
189
190    @Override
191    public String toString() {
192        StringBuilder buf = new StringBuilder();
193        switch (base) {
194            case 8:
195                buf.append('0');
196                break;
197            case 10:
198                break;
199            case 16:
200                buf.append("0x");
201                break;
202            case 2:
203                buf.append('b');
204                break;
205            default:
206                buf.append("[base-").append(base).append("]");
207                break;
208        }
209        buf.append(getIntegerPart());
210        if (getFractionalPart() != null)
211            buf.append('.').append(getFractionalPart());
212        if (getExponent() != null) {
213            buf.append(base > 10 ? 'p' : 'e');
214            buf.append(getExponent());
215        }
216        /*
217         if (appendFlags(buf, "ui", F_UNSIGNED | F_INT));
218         else if (appendFlags(buf, "ul", F_UNSIGNED | F_LONG));
219         else if (appendFlags(buf, "ull", F_UNSIGNED | F_LONGLONG));
220         else if (appendFlags(buf, "i", F_INT));
221         else if (appendFlags(buf, "l", F_LONG));
222         else if (appendFlags(buf, "ll", F_LONGLONG));
223         else if (appendFlags(buf, "f", F_FLOAT));
224         else if (appendFlags(buf, "d", F_DOUBLE));
225         */
226        return buf.toString();
227    }
228}