Skip to content

Commit

Permalink
Support max hex/oct/bin literals + Fix their uncaught exceptions
Browse files Browse the repository at this point in the history
- Support max 64-bit hex/oct/bin value literals, rather than only up to 63 bits.
- Fix uncaught exceptions when supplying hex/oct/bin literals that do not fit 63 bits (64 bits with the above mentioned change).
- Add tests for these number formats.
  • Loading branch information
Pieter12345 committed Nov 30, 2024
1 parent cf2aa81 commit bc22ff4
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 5 deletions.
41 changes: 36 additions & 5 deletions src/main/java/com/laytonsmith/core/Static.java
Original file line number Diff line number Diff line change
Expand Up @@ -592,21 +592,52 @@ public static Construct resolveConstruct(String val, Target t, boolean returnBar
throw new CREFormatException("Hex numbers must only contain digits 0-9, and the letters A-F, but \"" + val + "\" was found.", t);
}
if(VALID_HEX.matcher(val).matches()) {
//Hex number
return new CInt(Long.parseLong(val.substring(2), 16), t);

// Parse hex number. Special handling for 16-digit numbers to support setting all 64 bits of the value.
long longVal;
if(val.length() > 16 + 2) {
throw new CREFormatException("Hex numbers must contain at most 16 digits, but \"" + val + "\" was found.", t);
} else if(val.length() == 16 + 2) {
longVal = (Long.parseLong(val.substring(2, 10), 16) << 32) | Long.parseLong(val.substring(10, 18), 16);
} else {
longVal = Long.parseLong(val.substring(2), 16);
}
return new CInt(longVal, t);
}
if(INVALID_BINARY.matcher(val).matches()) {
throw new CREFormatException("Binary numbers must only contain digits 0 and 1, but \"" + val + "\" was found.", t);
}
if(VALID_BINARY.matcher(val).matches()) {
//Binary number
return new CInt(Long.parseLong(val.substring(2), 2), t);

// Parse binary number. Special handling for 64-digit numbers to support setting all 64 bits of the value.
long longVal;
if(val.length() > 64 + 2) {
throw new CREFormatException("Binary numbers must contain at most 64 digits, but \"" + val + "\" was found.", t);
} else if(val.length() == 64 + 2) {
longVal = (Long.parseLong(val.substring(2, 34), 2) << 32) | Long.parseLong(val.substring(34, 66), 2);
} else {
longVal = Long.parseLong(val.substring(2), 2);
}
return new CInt(longVal, t);
}
if(INVALID_OCTAL.matcher(val).matches()) {
throw new CREFormatException("Octal numbers must only contain digits 0-7, but \"" + val + "\" was found.", t);
}
if(VALID_OCTAL.matcher(val).matches()) {
return new CInt(Long.parseLong(val.substring(2), 8), t);

// Parse octal number. Special handling for 8-digit numbers to support setting all 64 bits of the value.
long longVal;
if(val.length() > 22 + 2) {
throw new CREFormatException("Octal numbers must contain at most 22 digits, but \"" + val + "\" was found.", t);
} else if(val.length() == 22 + 2) {
if(val.charAt(2) != '1') {
throw new CREFormatException("Octal number exceeds maximum 64-bit value 0o1777777777777777777777. Found \"" + val + "\".", t);
}
longVal = Long.parseLong(val.substring(3), 8) | (1L << 63);
} else {
longVal = Long.parseLong(val.substring(2), 8);
}
return new CInt(longVal, t);
}
if(INVALID_DECIMAL.matcher(val).matches()) {
throw new CREFormatException("Decimal numbers must only contain digits, but \"" + val + "\" was found.", t);
Expand Down
16 changes: 16 additions & 0 deletions src/test/java/com/laytonsmith/core/TestStatic.java
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,22 @@ public void testResolveConstruct() {
assertTrue(Static.resolveConstruct("1.1", Target.UNKNOWN) instanceof CDouble);
assertTrue(Static.resolveConstruct("astring", Target.UNKNOWN) instanceof CString);
assertTrue(Static.resolveConstruct("string", Target.UNKNOWN) instanceof CClassType);
assertTrue(getResolveConstructLong("0xFF") == 0xFF);
assertTrue(getResolveConstructLong("0xABCDEF0123456789") == 0xABCDEF0123456789L); // All chars.
assertTrue(getResolveConstructLong("0xFFAFFFFFFFF0FFFF") == 0xFFAFFFFFFFF0FFFFL);
assertTrue(getResolveConstructLong("0xFFFFFFFFFFFFFFFF") == 0xFFFFFFFFFFFFFFFFL); // Max value.
assertTrue(getResolveConstructLong("0b100") == 0b100);
assertTrue(getResolveConstructLong("0b1111011111111011111111111011111111111111111111110111111111111110")
== 0b1111011111111011111111111011111111111111111111110111111111111110L);
assertTrue(getResolveConstructLong("0b1111111111111111111111111111111111111111111111111111111111111111")
== 0b1111111111111111111111111111111111111111111111111111111111111111L); // Max value.
assertTrue(getResolveConstructLong("0o76543210") == 076543210L); // All chars.
assertTrue(getResolveConstructLong("0o1737745677477125767277") == 01737745677477125767277L);
assertTrue(getResolveConstructLong("0o1777777777777777777777") == 01777777777777777777777L); // Max value.
}

private static long getResolveConstructLong(String val) {
return ((CInt) Static.resolveConstruct(val, Target.UNKNOWN)).getInt();
}

}

0 comments on commit bc22ff4

Please sign in to comment.