1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.jexl3.parser;
18
19 import java.io.Serializable;
20 import java.math.BigDecimal;
21 import java.math.BigInteger;
22 import java.text.DecimalFormat;
23 import java.text.DecimalFormatSymbols;
24 import java.util.Locale;
25
26
27
28
29 public final class NumberParser implements Serializable {
30
31
32
33 private static final long serialVersionUID = 1L;
34
35 private Number literal = null;
36
37 private Class<? extends Number> clazz = null;
38
39 static final DecimalFormat BIGDF = new DecimalFormat("0.0b", new DecimalFormatSymbols(Locale.ENGLISH));
40
41 @Override
42 public String toString() {
43 if (literal == null || clazz == null || Double.isNaN(literal.doubleValue())) {
44 return "NaN";
45 }
46 if (BigDecimal.class.equals(clazz)) {
47 synchronized (BIGDF) {
48 return BIGDF.format(literal);
49 }
50 }
51 final StringBuilder strb = new StringBuilder(literal.toString());
52 if (Float.class.equals(clazz)) {
53 strb.append('f');
54 } else if (Double.class.equals(clazz)) {
55 strb.append('d');
56 } else if (BigInteger.class.equals(clazz)) {
57 strb.append('h');
58 } else if (Long.class.equals(clazz)) {
59 strb.append('l');
60 }
61 return strb.toString();
62 }
63
64
65 Class<? extends Number> getLiteralClass() {
66 return clazz;
67 }
68
69 boolean isInteger() {
70 return Integer.class.equals(clazz);
71 }
72
73 Number getLiteralValue() {
74 return literal;
75 }
76
77 private static boolean isNegative(final Token token) {
78 return token != null && "-".equals(token.image);
79 }
80
81 static Number parseInteger(final Token negative, final Token s) {
82 return new NumberParser().assignNatural(isNegative(negative), s.image).getLiteralValue();
83 }
84
85 static Number parseDouble(final Token negative, final Token s) {
86 return new NumberParser().assignReal(isNegative(negative), s.image).getLiteralValue();
87 }
88
89
90
91
92
93
94
95 NumberParser assignNatural(final String str) {
96 String s;
97
98 final boolean negative;
99 switch (str.charAt(0)) {
100 case '-':
101 negative = true;
102 s = str.substring(1);
103 break;
104 case '+':
105 negative = false;
106 s = str.substring(1);
107 break;
108 default:
109 negative = false;
110 s = str;
111 }
112 return assignNatural(negative, s);
113 }
114
115
116
117
118
119
120
121
122 NumberParser assignNatural(final boolean negative, final String natural) {
123 String s = natural;
124 Number result;
125 Class<? extends Number> rclass;
126
127 final int base;
128 if (s.charAt(0) == '0') {
129 if ((s.length() > 1 && (s.charAt(1) == 'x' || s.charAt(1) == 'X'))) {
130 base = 16;
131 s = s.substring(2);
132 } else {
133 base = 8;
134 }
135 } else {
136 base = 10;
137 }
138
139 final int last = s.length() - 1;
140 switch (s.charAt(last)) {
141 case 'l':
142 case 'L': {
143 rclass = Long.class;
144 final long l = Long.parseLong(s.substring(0, last), base);
145 result = negative? -l : l;
146 break;
147 }
148 case 'h':
149 case 'H': {
150 rclass = BigInteger.class;
151 final BigInteger bi = new BigInteger(s.substring(0, last), base);
152 result = negative? bi.negate() : bi;
153 break;
154 }
155 default: {
156
157 rclass = Integer.class;
158 try {
159 final int i = Integer.parseInt(s, base);
160 result = negative? -i : i;
161 } catch (final NumberFormatException take2) {
162 try {
163 final long l = Long.parseLong(s, base);
164 result = negative? -l : l;
165 } catch (final NumberFormatException take3) {
166 final BigInteger bi = new BigInteger(s, base);
167 result = negative? bi.negate() : bi;
168 }
169 }
170 }
171 }
172 literal = result;
173 clazz = rclass;
174 return this;
175 }
176
177
178
179
180
181
182
183 NumberParser assignReal(final String str) {
184 String s;
185
186 final boolean negative;
187 switch (str.charAt(0)) {
188 case '-':
189 negative = true;
190 s = str.substring(1);
191 break;
192 case '+':
193 negative = false;
194 s = str.substring(1);
195 break;
196 default:
197 negative = false;
198 s = str;
199 }
200 return assignReal(negative, s);
201 }
202
203
204
205
206
207
208
209
210 NumberParser assignReal(final boolean negative, final String s) {
211 Number result;
212 Class<? extends Number> rclass;
213 if ("#NaN".equals(s) || "NaN".equals(s)) {
214 result = Double.NaN;
215 rclass = Double.class;
216 } else {
217 final int last = s.length() - 1;
218 switch (s.charAt(last)) {
219 case 'b':
220 case 'B': {
221 rclass = BigDecimal.class;
222 final BigDecimal bd = new BigDecimal(s.substring(0, last));
223 result = negative? bd.negate() : bd;
224 break;
225 }
226 case 'f':
227 case 'F': {
228 rclass = Float.class;
229 final float f4 = Float.parseFloat(s.substring(0, last));
230 result = negative? -f4 : f4;
231 break;
232 }
233 case 'd':
234 case 'D':
235 rclass = Double.class;
236 final double f8 = Double.parseDouble(s.substring(0, last));
237 result = negative? -f8 : f8;
238 break;
239 default: {
240
241 rclass = Double.class;
242 try {
243 final double d = Double.parseDouble(s);
244 result = negative? -d : d;
245 } catch (final NumberFormatException take3) {
246 final BigDecimal bd = new BigDecimal(s);
247 result = negative? bd.negate() : bd;
248 }
249 break;
250 }
251 }
252 }
253 literal = result;
254 clazz = rclass;
255 return this;
256 }
257
258 }