+++ /dev/null
-package net.mograsim.plugin.asm;
-
-import static java.lang.String.format;
-
-import java.math.BigInteger;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-public final class AsmNumberUtil
-{
-
- private AsmNumberUtil()
- {
-
- }
-
- private static final String sgnPat = "([-+]?)";
- private static final String binPat = "((?:[01]+_)*[01]+)";
- private static final String octPat = "((?:[0-7]+_)*[0-7]+)";
- private static final String decPat = "((?:[0-9]+_)*[0-9]+)";
- private static final String hexPat = "((?:[0-9a-f]+_)*[0-9a-f]+)";
-
- private static final String preferredBinPat = "%1$s0b%2$s";
- private static final String preferredOctPat = "%s%sq";
- private static final String preferredDecPat = "%s%s";
- private static final String preferredHexPat = "%1$s0x%2$s";
-
- static final Pattern numberBin = Pattern.compile(format(preferredBinPat + "|%1$s%2$sb", sgnPat, binPat), Pattern.CASE_INSENSITIVE);
- static final Pattern numberOct = Pattern.compile(format(preferredOctPat, sgnPat, octPat), Pattern.CASE_INSENSITIVE);
- static final Pattern numberDec = Pattern.compile(format(preferredDecPat, sgnPat, decPat));
- static final Pattern numberHex = Pattern.compile(format(preferredHexPat + "|%1$s%2$sh", sgnPat, hexPat), Pattern.CASE_INSENSITIVE);
- static final Pattern numberFloat = Pattern.compile(format("%1$s%2$s(?:\\.%2$s)?(?:e%1$s%2$s)?", sgnPat, decPat),
- Pattern.CASE_INSENSITIVE);
-
- public static boolean isPrefix(CharSequence cs, Pattern p)
- {
- Matcher m = p.matcher(cs);
- return m.matches() || m.hitEnd();
- }
-
- public static boolean isBinary(CharSequence cs)
- {
- return numberBin.matcher(cs).matches();
- }
-
- public static boolean isOctal(CharSequence cs)
- {
- return numberOct.matcher(cs).matches();
- }
-
- public static boolean isDecimal(CharSequence cs)
- {
- return numberDec.matcher(cs).matches();
- }
-
- public static boolean isHexadecimal(CharSequence cs)
- {
- return numberHex.matcher(cs).matches();
- }
-
- public static boolean isFloatingPoint(CharSequence cs)
- {
- return numberFloat.matcher(cs).matches();
- }
-
- public static boolean isNumber(CharSequence cs)
- {
- return getType(cs) != NumberType.NONE;
- }
-
- public static boolean quickCheckForNumber(CharSequence cs)
- {
- if (cs.length() == 0 || !isStart(cs.charAt(0)))
- return false;
- return cs.length() == 1 || isPart(cs.charAt(1));
- }
-
- public static boolean isStart(int c)
- {
- return isDigit(c) || c == '+' || c == '-';
- }
-
- public static boolean isDigit(int c)
- {
- return ('0' <= c && c <= '9') || ('A' <= c && c <= 'F') || ('a' <= c && c <= 'f');
- }
-
- public static boolean isPart(int c)
- {
- return isDigit(c) || isMarker(Character.toLowerCase(c));
- }
-
- public static boolean isMarker(int lowerCase)
- {
- switch (lowerCase)
- {
- case '.':
- case '_':
- case '+':
- case '-':
- case 'e':
- case 'x':
- case 'b':
- case 'q':
- case 'h':
- return true;
- default:
- return false;
- }
- }
-
- public static NumberType getType(CharSequence cs)
- {
- if (!quickCheckForNumber(cs))
- return NumberType.NONE;
- if (isDecimal(cs))
- return NumberType.DECIMAL;
- if (isHexadecimal(cs))
- return NumberType.HEXADECIMAL;
- if (isBinary(cs))
- return NumberType.BINARY;
- if (isOctal(cs))
- return NumberType.OCTAL;
- if (isFloatingPoint(cs))
- return NumberType.FLOATINGPOINT;
- return NumberType.NONE;
- }
-
- /**
- * Checks if the {@link CharSequence} is a prefix of a valid number, and returns the NumberType it is a prefix of. If a String is a
- * prefix of multiple different {@link NumberType}s, the one with the smallest radix is returned. If no valid {@link NumberType} is
- * found, {@link NumberType#NONE} is returned.
- *
- * @param cs The potential prefix
- * @return The type the {@link CharSequence} is a prefix of
- */
- public static NumberType prefixOfType(CharSequence cs)
- {
- if (isPrefix(cs, numberBin))
- return NumberType.BINARY;
- if (isPrefix(cs, numberOct))
- return NumberType.OCTAL;
- if (isPrefix(cs, numberDec))
- return NumberType.DECIMAL;
- if (isPrefix(cs, numberHex))
- return NumberType.HEXADECIMAL;
- if (isPrefix(cs, numberFloat))
- return NumberType.FLOATINGPOINT;
- return NumberType.NONE;
- }
-
- private static CharSequence extractSignAndDigits(NumberType type, CharSequence cs)
- {
- return type.numberPattern.matcher(cs).replaceAll("$1$2").replaceAll("_", "");
- }
-
- /**
- * Computes the {@link BigInteger} value of a {@link CharSequence}, by determining the {@link NumberType} and parsing the number with
- * the determined radix.
- *
- * @throws NumberFormatException if the {@link CharSequence} does not match any of the expected number patterns
- */
- public static BigInteger valueOf(CharSequence cs)
- {
- NumberType type = getType(cs);
- if (NumberType.NONE.equals(type))
- throw new NumberFormatException();
- return new BigInteger(extractSignAndDigits(type, cs).toString(), type.radix);
- }
-
- /**
- * Formats a {@link BigInteger} in accordance with the pattern associated with the supplied {@link NumberType}
- */
- public static String toString(BigInteger number, NumberType type)
- {
- String pattern;
- switch (type)
- {
- case BINARY:
- pattern = preferredBinPat;
- break;
- case OCTAL:
- pattern = preferredOctPat;
- break;
- default:
- case DECIMAL:
- pattern = preferredDecPat;
- break;
- case HEXADECIMAL:
- pattern = preferredHexPat;
- }
- if (number.signum() < 0)
- return String.format(pattern, "-", number.abs().toString(type.radix));
- return String.format(pattern, "", number.toString(type.radix));
- }
-
- public enum NumberType
- {
- NONE(-1, null), BINARY(2, AsmNumberUtil.numberBin), OCTAL(8, AsmNumberUtil.numberOct), DECIMAL(10, AsmNumberUtil.numberDec),
- HEXADECIMAL(16, AsmNumberUtil.numberHex), FLOATINGPOINT(10, AsmNumberUtil.numberFloat);
-
- public final int radix;
- final Pattern numberPattern;
-
- NumberType(int radix, Pattern numberPattern)
- {
- this.radix = radix;
- this.numberPattern = numberPattern;
- }
- }
-}