1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47 package org.codehaus.groovy.syntax;
48
49 import java.math.BigInteger;
50 import java.math.BigDecimal;
51
52 /***
53 * Helper class for processing Groovy numeric literals.
54 *
55 * @author Brian Larson
56 * @author <a href="mailto:cpoirier@dreaming.org">Chris Poirier</a>
57 *
58 * @version $Id: Numbers.java,v 1.3 2004/04/07 20:19:20 cpoirier Exp $
59 */
60
61 public class Numbers
62 {
63
64
65
66
67
68
69
70 /***
71 * Returns true if the specified character is a base-10 digit.
72 */
73
74 public static boolean isDigit( char c )
75 {
76 return c >= '0' && c <= '9';
77 }
78
79
80 /***
81 * Returns true if the specific character is a base-8 digit.
82 */
83
84 public static boolean isOctalDigit( char c )
85 {
86 return c >= '0' && c <= '7';
87 }
88
89
90 /***
91 * Returns true if the specified character is a base-16 digit.
92 */
93
94 public static boolean isHexDigit( char c )
95 {
96 return isDigit(c) || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f');
97 }
98
99
100
101 /***
102 * Returns true if the specified character is a valid type specifier
103 * for a numeric value.
104 */
105
106 public static boolean isNumericTypeSpecifier( char c, boolean isDecimal )
107 {
108 if( isDecimal )
109 {
110 switch( c )
111 {
112 case 'G':
113 case 'g':
114 case 'D':
115 case 'd':
116 case 'F':
117 case 'f':
118 return true;
119 }
120 }
121 else
122 {
123 switch( c )
124 {
125 case 'G':
126 case 'g':
127 case 'I':
128 case 'i':
129 case 'L':
130 case 'l':
131 return true;
132 }
133 }
134
135 return false;
136 }
137
138
139
140
141
142
143
144
145
146 private static final BigInteger MAX_LONG = BigInteger.valueOf(Long.MAX_VALUE);
147 private static final BigInteger MIN_LONG = BigInteger.valueOf(Long.MIN_VALUE);
148
149 private static final BigInteger MAX_INTEGER = BigInteger.valueOf(Integer.MAX_VALUE);
150 private static final BigInteger MIN_INTEGER = BigInteger.valueOf(Integer.MIN_VALUE);
151
152 private static final BigDecimal MAX_DOUBLE = new BigDecimal(String.valueOf(Double.MAX_VALUE));
153 private static final BigDecimal MIN_DOUBLE = MAX_DOUBLE.negate();
154
155 private static final BigDecimal MAX_FLOAT = new BigDecimal(String.valueOf(Float.MAX_VALUE));
156 private static final BigDecimal MIN_FLOAT = MAX_FLOAT.negate();
157
158
159
160 /***
161 * Builds a Number from the given integer descriptor. Creates the narrowest
162 * type possible, or a specific type, if specified.
163 *
164 * @param text literal text to parse
165 * @return instantiated Number object
166 * @throws NumberFormatException if the number does not fit within the type
167 * requested by the type specifier suffix (invalid numbers don't make
168 * it here)
169 */
170
171 public static Number parseInteger( String text )
172 {
173 char c = ' ';
174 int length = text.length();
175
176
177
178
179
180 boolean negative = false;
181 if( (c = text.charAt(0)) == '-' || c == '+' )
182 {
183 negative = (c == '-');
184 text = text.substring( 1, length );
185 length -= 1;
186 }
187
188
189
190
191
192 int radix = 10;
193 if( text.charAt(0) == '0' && length > 1 )
194 {
195 if( (c = text.charAt(1)) == 'X' || c == 'x' )
196 {
197 radix = 16;
198 text = text.substring( 2, length);
199 length -= 2;
200 }
201 else
202 {
203 radix = 8;
204 }
205 }
206
207
208
209
210
211
212 char type = 'x';
213 if( isNumericTypeSpecifier(text.charAt(length-1), false) )
214 {
215 type = Character.toLowerCase( text.charAt(length-1) );
216 text = text.substring( 0, length-1);
217
218 length -= 1;
219 }
220
221
222
223
224
225 if( negative )
226 {
227 text = "-" + text;
228 }
229
230
231
232
233
234
235 switch (type)
236 {
237 case 'i':
238 return new Integer( Integer.parseInt(text, radix) );
239
240 case 'l':
241 return new Long( Long.parseLong(text, radix) );
242
243 case 'g':
244 return new BigInteger( text, radix );
245
246 default:
247
248
249
250
251
252 BigInteger value = new BigInteger( text, radix );
253
254 if( value.compareTo(MAX_INTEGER) <= 0 && value.compareTo(MIN_INTEGER) >= 0 )
255 {
256 return new Integer(value.intValue());
257 }
258 else if( value.compareTo(MAX_LONG) <= 0 && value.compareTo(MIN_LONG) >= 0 )
259 {
260 return new Long(value.longValue());
261 }
262
263 return value;
264 }
265 }
266
267
268
269 /***
270 * Builds a Number from the given decimal descriptor. Uses BigDecimal,
271 * unless, Double or Float is requested.
272 *
273 * @param text literal text to parse
274 * @return instantiated Number object
275 * @throws NumberFormatException if the number does not fit within the type
276 * requested by the type specifier suffix (invalid numbers don't make
277 * it here)
278 */
279
280 public static Number parseDecimal( String text )
281 {
282 int length = text.length();
283
284
285
286
287
288
289 char type = 'x';
290 if( isNumericTypeSpecifier(text.charAt(length-1), true) )
291 {
292 type = Character.toLowerCase( text.charAt(length-1) );
293 text = text.substring( 0, length-1 );
294
295 length -= 1;
296 }
297
298
299
300
301
302 BigDecimal value = new BigDecimal( text );
303 switch( type )
304 {
305 case 'f':
306 if( value.compareTo(MAX_FLOAT) <= 0 && value.compareTo(MIN_FLOAT) >= 0)
307 {
308 return new Float( text );
309 }
310 throw new NumberFormatException( "out of range" );
311
312 case 'd':
313 if( value.compareTo(MAX_DOUBLE) <= 0 && value.compareTo(MIN_DOUBLE) >= 0)
314 {
315 return new Double( text );
316 }
317 throw new NumberFormatException( "out of range" );
318
319 case 'g':
320 default:
321 return value;
322 }
323 }
324
325 }