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