KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > codehaus > groovy > syntax > Numbers


1 /*
2  $Id: Numbers.java,v 1.3 2004/04/07 20:19:20 cpoirier Exp $
3
4  Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
5
6  Redistribution and use of this software and associated documentation
7  ("Software"), with or without modification, are permitted provided
8  that the following conditions are met:
9
10  1. Redistributions of source code must retain copyright
11     statements and notices. Redistributions must also contain a
12     copy of this document.
13
14  2. Redistributions in binary form must reproduce the
15     above copyright notice, this list of conditions and the
16     following disclaimer in the documentation and/or other
17     materials provided with the distribution.
18
19  3. The name "groovy" must not be used to endorse or promote
20     products derived from this Software without prior written
21     permission of The Codehaus. For written permission,
22     please contact info@codehaus.org.
23
24  4. Products derived from this Software may not be called "groovy"
25     nor may "groovy" appear in their names without prior written
26     permission of The Codehaus. "groovy" is a registered
27     trademark of The Codehaus.
28
29  5. Due credit should be given to The Codehaus -
30     http://groovy.codehaus.org/
31
32  THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
33  ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
34  NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
35  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
36  THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
37  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
38  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
39  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
41  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
42  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
43  OF THE POSSIBILITY OF SUCH DAMAGE.
44
45  */

46
47 package org.codehaus.groovy.syntax;
48
49 import java.math.BigInteger JavaDoc;
50 import java.math.BigDecimal JavaDoc;
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
// LEXING SUPPORT
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
// PARSING SUPPORT
144

145
146     private static final BigInteger JavaDoc MAX_LONG = BigInteger.valueOf(Long.MAX_VALUE);
147     private static final BigInteger JavaDoc MIN_LONG = BigInteger.valueOf(Long.MIN_VALUE);
148
149     private static final BigInteger JavaDoc MAX_INTEGER = BigInteger.valueOf(Integer.MAX_VALUE);
150     private static final BigInteger JavaDoc MIN_INTEGER = BigInteger.valueOf(Integer.MIN_VALUE);
151
152     private static final BigDecimal JavaDoc MAX_DOUBLE = new BigDecimal JavaDoc(String.valueOf(Double.MAX_VALUE));
153     private static final BigDecimal JavaDoc MIN_DOUBLE = MAX_DOUBLE.negate();
154
155     private static final BigDecimal JavaDoc MAX_FLOAT = new BigDecimal JavaDoc(String.valueOf(Float.MAX_VALUE));
156     private static final BigDecimal JavaDoc 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 JavaDoc parseInteger( String JavaDoc text )
172     {
173         char c = ' ';
174         int length = text.length();
175
176
177         //
178
// Strip off the sign, if present
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
// Determine radix (default is 10).
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
// Strip off any type specifier and convert it to lower
210
// case, if present.
211

212         char type = 'x'; // pick best fit
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
// Add the sign back, if necessary
224

225         if( negative )
226         {
227             text = "-" + text;
228         }
229
230
231         //
232
// Build the specified type or, if no type was specified, the
233
// smallest type in which the number will fit.
234

235         switch (type)
236         {
237             case 'i':
238                 return new Integer JavaDoc( Integer.parseInt(text, radix) );
239
240             case 'l':
241                 return new Long JavaDoc( Long.parseLong(text, radix) );
242
243             case 'g':
244                 return new BigInteger JavaDoc( text, radix );
245
246             default:
247
248                 //
249
// If not specified, we will return the narrowest possible
250
// of Integer, Long, and BigInteger.
251

252                 BigInteger JavaDoc value = new BigInteger JavaDoc( text, radix );
253
254                 if( value.compareTo(MAX_INTEGER) <= 0 && value.compareTo(MIN_INTEGER) >= 0 )
255                 {
256                     return new Integer JavaDoc(value.intValue());
257                 }
258                 else if( value.compareTo(MAX_LONG) <= 0 && value.compareTo(MIN_LONG) >= 0 )
259                 {
260                     return new Long JavaDoc(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 JavaDoc parseDecimal( String JavaDoc text )
281     {
282         int length = text.length();
283
284
285         //
286
// Strip off any type specifier and convert it to lower
287
// case, if present.
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
// Build the specified type or default to BigDecimal
301

302         BigDecimal JavaDoc value = new BigDecimal JavaDoc( 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 JavaDoc( text );
309                 }
310                 throw new NumberFormatException JavaDoc( "out of range" );
311
312             case 'd':
313                 if( value.compareTo(MAX_DOUBLE) <= 0 && value.compareTo(MIN_DOUBLE) >= 0)
314                 {
315                     return new Double JavaDoc( text );
316                 }
317                 throw new NumberFormatException JavaDoc( "out of range" );
318
319             case 'g':
320             default:
321                 return value;
322         }
323     }
324
325 }
326
Popular Tags