|
| 1 | +/** |
| 2 | + * Provides predicates for working with numeric values and their string |
| 3 | + * representations. |
| 4 | + */ |
| 5 | + |
| 6 | +/** |
| 7 | + * Gets the integer value of `binary` when interpreted as binary. `binary` must |
| 8 | + * contain only the digits 0 and 1. For values greater than |
| 9 | + * 01111111111111111111111111111111 (2^31-1, the maximum value that `int` can |
| 10 | + * represent), there is no result. |
| 11 | + * |
| 12 | + * ``` |
| 13 | + * "0" => 0 |
| 14 | + * "01" => 1 |
| 15 | + * "1010101" => 85 |
| 16 | + * ``` |
| 17 | + */ |
| 18 | +bindingset[binary] |
| 19 | +int parseBinaryInt(string binary) { |
| 20 | + exists(string stripped | stripped = stripLeadingZeros(binary) | |
| 21 | + stripped.length() <= 31 and |
| 22 | + result >= 0 and |
| 23 | + result = |
| 24 | + sum(int index, string c, int digit | |
| 25 | + c = stripped.charAt(index) and |
| 26 | + digit = "01".indexOf(c) |
| 27 | + | |
| 28 | + twoToThe(stripped.length() - 1 - index) * digit |
| 29 | + ) |
| 30 | + ) |
| 31 | +} |
| 32 | + |
| 33 | +/** |
| 34 | + * Gets the integer value of `hex` when interpreted as hex. `hex` must be a |
| 35 | + * valid hexadecimal string. For values greater than 7FFFFFFF (2^31-1, the |
| 36 | + * maximum value that `int` can represent), there is no result. |
| 37 | + * |
| 38 | + * ``` |
| 39 | + * "0" => 0 |
| 40 | + * "FF" => 255 |
| 41 | + * "f00d" => 61453 |
| 42 | + * ``` |
| 43 | + */ |
| 44 | +bindingset[hex] |
| 45 | +int parseHexInt(string hex) { |
| 46 | + exists(string stripped | stripped = stripLeadingZeros(hex) | |
| 47 | + stripped.length() <= 8 and |
| 48 | + result >= 0 and |
| 49 | + result = |
| 50 | + sum(int index, string c | |
| 51 | + c = stripped.charAt(index) |
| 52 | + | |
| 53 | + sixteenToThe(stripped.length() - 1 - index) * toHex(c) |
| 54 | + ) |
| 55 | + ) |
| 56 | +} |
| 57 | + |
| 58 | +/** |
| 59 | + * Gets the integer value of `octal` when interpreted as octal. `octal` must be |
| 60 | + * a valid octal string containing only the digits 0-7. For values greater than |
| 61 | + * 17777777777 (2^31-1, the maximum value that `int` can represent), there is no |
| 62 | + * result. |
| 63 | + * |
| 64 | + * ``` |
| 65 | + * "0" => 0 |
| 66 | + * "77" => 63 |
| 67 | + * "76543210" => 16434824 |
| 68 | + * ``` |
| 69 | + */ |
| 70 | +bindingset[octal] |
| 71 | +int parseOctalInt(string octal) { |
| 72 | + exists(string stripped | stripped = stripLeadingZeros(octal) | |
| 73 | + stripped.length() <= 11 and |
| 74 | + result >= 0 and |
| 75 | + result = |
| 76 | + sum(int index, string c, int digit | |
| 77 | + c = stripped.charAt(index) and |
| 78 | + digit = "01234567".indexOf(c) |
| 79 | + | |
| 80 | + eightToThe(stripped.length() - 1 - index) * digit |
| 81 | + ) |
| 82 | + ) |
| 83 | +} |
| 84 | + |
| 85 | +/** Gets the integer value of the `hex` char. */ |
| 86 | +private int toHex(string hex) { |
| 87 | + hex = [0 .. 9].toString() and |
| 88 | + result = hex.toInt() |
| 89 | + or |
| 90 | + result = 10 and hex = ["a", "A"] |
| 91 | + or |
| 92 | + result = 11 and hex = ["b", "B"] |
| 93 | + or |
| 94 | + result = 12 and hex = ["c", "C"] |
| 95 | + or |
| 96 | + result = 13 and hex = ["d", "D"] |
| 97 | + or |
| 98 | + result = 14 and hex = ["e", "E"] |
| 99 | + or |
| 100 | + result = 15 and hex = ["f", "F"] |
| 101 | +} |
| 102 | + |
| 103 | +/** |
| 104 | + * Gets the value of 16 to the power of `n`. Holds only for `n` in the range |
| 105 | + * 0..7 (inclusive). |
| 106 | + */ |
| 107 | +int sixteenToThe(int n) { |
| 108 | + // 16**7 is the largest power of 16 that fits in an int. |
| 109 | + n in [0 .. 7] and result = 1.bitShiftLeft(4 * n) |
| 110 | +} |
| 111 | + |
| 112 | +/** |
| 113 | + * Gets the value of 8 to the power of `n`. Holds only for `n` in the range |
| 114 | + * 0..10 (inclusive). |
| 115 | + */ |
| 116 | +int eightToThe(int n) { |
| 117 | + // 8**10 is the largest power of 8 that fits in an int. |
| 118 | + n in [0 .. 10] and result = 1.bitShiftLeft(3 * n) |
| 119 | +} |
| 120 | + |
| 121 | +/** |
| 122 | + * Gets the value of 2 to the power of `n`. Holds only for `n` in the range |
| 123 | + * 0..30 (inclusive). |
| 124 | + */ |
| 125 | +int twoToThe(int n) { n in [0 .. 30] and result = 1.bitShiftLeft(n) } |
| 126 | + |
| 127 | +/** Gets `s` with any leading "0" characters removed. */ |
| 128 | +bindingset[s] |
| 129 | +private string stripLeadingZeros(string s) { result = s.regexpCapture("0*(.*)", 1) } |
0 commit comments