Added valueOf(...) method to AsmNumberUtil to parse the number formats
[Mograsim.git] / net.mograsim.plugin.core / src / net / mograsim / plugin / asm / AsmNumberUtil.java
1 package net.mograsim.plugin.asm;
2
3 import static java.lang.String.format;
4
5 import java.math.BigInteger;
6 import java.util.regex.Pattern;
7
8 public final class AsmNumberUtil
9 {
10
11         private AsmNumberUtil()
12         {
13
14         }
15
16         private static final String sgnPat = "([-+]?)";
17         private static final String binPat = "((?:[01]+_)*[01]+)";
18         private static final String octPat = "((?:[0-7]+_)*[0-7]+)";
19         private static final String decPat = "((?:[0-9]+_)*[0-9]+)";
20         private static final String hexPat = "((?:[0-9a-f]+_)*[0-9a-f]+)";
21         static final Pattern numberBin = Pattern.compile(format("%1$s0b%2$s|%1$s%2$sb", sgnPat, binPat), Pattern.CASE_INSENSITIVE);
22         static final Pattern numberOct = Pattern.compile(format("%s%sq", sgnPat, octPat), Pattern.CASE_INSENSITIVE);
23         static final Pattern numberDec = Pattern.compile(format("%s%s", sgnPat, decPat));
24         static final Pattern numberHex = Pattern.compile(format("%1$s0x%2$s|%1$s%2$sh", sgnPat, hexPat), Pattern.CASE_INSENSITIVE);
25         static final Pattern numberFloat = Pattern.compile(format("%1$s%2$s(?:\\.%2$s)?(?:e%1$s%2$s)?", sgnPat, decPat),
26                         Pattern.CASE_INSENSITIVE);
27
28         public static boolean isBinary(CharSequence cs)
29         {
30                 return numberBin.matcher(cs).matches();
31         }
32
33         public static boolean isOctal(CharSequence cs)
34         {
35                 return numberOct.matcher(cs).matches();
36         }
37
38         public static boolean isDecimal(CharSequence cs)
39         {
40                 return numberDec.matcher(cs).matches();
41         }
42
43         public static boolean isHexadecimal(CharSequence cs)
44         {
45                 return numberHex.matcher(cs).matches();
46         }
47
48         public static boolean isFloatingPoint(CharSequence cs)
49         {
50                 return numberFloat.matcher(cs).matches();
51         }
52
53         public static boolean isNumber(CharSequence cs)
54         {
55                 return getType(cs) != NumberType.NONE;
56         }
57
58         public static boolean quickCheckForNumber(CharSequence cs)
59         {
60                 if (cs.length() == 0 || !isStart(cs.charAt(0)))
61                         return false;
62                 return cs.length() == 1 || isPart(cs.charAt(1));
63         }
64
65         public static boolean isStart(int c)
66         {
67                 return isDigit(c) || c == '+' || c == '-';
68         }
69
70         public static boolean isDigit(int c)
71         {
72                 return ('0' <= c && c <= '9') || ('A' <= c && c <= 'F') || ('a' <= c && c <= 'f');
73         }
74
75         public static boolean isPart(int c)
76         {
77                 return isDigit(c) || isMarker(Character.toLowerCase(c));
78         }
79
80         public static boolean isMarker(int lowerCase)
81         {
82                 switch (lowerCase)
83                 {
84                 case '.':
85                 case '_':
86                 case '+':
87                 case '-':
88                 case 'e':
89                 case 'x':
90                 case 'b':
91                 case 'q':
92                 case 'h':
93                         return true;
94                 default:
95                         return false;
96                 }
97         }
98
99         public static NumberType getType(CharSequence cs)
100         {
101                 if (!quickCheckForNumber(cs))
102                         return NumberType.NONE;
103                 if (isDecimal(cs))
104                         return NumberType.DECIMAL;
105                 if (isHexadecimal(cs))
106                         return NumberType.HEXADECIMAL;
107                 if (isBinary(cs))
108                         return NumberType.BINARY;
109                 if (isOctal(cs))
110                         return NumberType.OCTAL;
111                 if (isFloatingPoint(cs))
112                         return NumberType.FLOATINGPOINT;
113                 return NumberType.NONE;
114         }
115
116         private static CharSequence extractSignAndDigits(NumberType type, CharSequence cs)
117         {
118                 return type.numberPattern.matcher(cs).replaceAll("$1$2").replaceAll("_", "");
119         }
120
121         public static BigInteger valueOf(CharSequence cs)
122         {
123                 NumberType type = getType(cs);
124                 if (NumberType.NONE.equals(type))
125                         throw new NumberFormatException();
126                 return new BigInteger(extractSignAndDigits(type, cs).toString(), type.radix);
127         }
128
129         public enum NumberType
130         {
131                 NONE(-1, null), BINARY(2, AsmNumberUtil.numberBin), OCTAL(8, AsmNumberUtil.numberOct), DECIMAL(10, AsmNumberUtil.numberDec),
132                 HEXADECIMAL(16, AsmNumberUtil.numberHex), FLOATINGPOINT(10, AsmNumberUtil.numberFloat);
133
134                 public final int radix;
135                 private final Pattern numberPattern;
136
137                 NumberType(int radix, Pattern numberPattern)
138                 {
139                         this.radix = radix;
140                         this.numberPattern = numberPattern;
141                 }
142         }
143 }