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