Skip to content

Commit bc22ff4

Browse files
committed
Support max hex/oct/bin literals + Fix their uncaught exceptions
- 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.
1 parent cf2aa81 commit bc22ff4

File tree

2 files changed

+52
-5
lines changed

2 files changed

+52
-5
lines changed

src/main/java/com/laytonsmith/core/Static.java

+36-5
Original file line numberDiff line numberDiff line change
@@ -592,21 +592,52 @@ public static Construct resolveConstruct(String val, Target t, boolean returnBar
592592
throw new CREFormatException("Hex numbers must only contain digits 0-9, and the letters A-F, but \"" + val + "\" was found.", t);
593593
}
594594
if(VALID_HEX.matcher(val).matches()) {
595-
//Hex number
596-
return new CInt(Long.parseLong(val.substring(2), 16), t);
595+
596+
// Parse hex number. Special handling for 16-digit numbers to support setting all 64 bits of the value.
597+
long longVal;
598+
if(val.length() > 16 + 2) {
599+
throw new CREFormatException("Hex numbers must contain at most 16 digits, but \"" + val + "\" was found.", t);
600+
} else if(val.length() == 16 + 2) {
601+
longVal = (Long.parseLong(val.substring(2, 10), 16) << 32) | Long.parseLong(val.substring(10, 18), 16);
602+
} else {
603+
longVal = Long.parseLong(val.substring(2), 16);
604+
}
605+
return new CInt(longVal, t);
597606
}
598607
if(INVALID_BINARY.matcher(val).matches()) {
599608
throw new CREFormatException("Binary numbers must only contain digits 0 and 1, but \"" + val + "\" was found.", t);
600609
}
601610
if(VALID_BINARY.matcher(val).matches()) {
602-
//Binary number
603-
return new CInt(Long.parseLong(val.substring(2), 2), t);
611+
612+
// Parse binary number. Special handling for 64-digit numbers to support setting all 64 bits of the value.
613+
long longVal;
614+
if(val.length() > 64 + 2) {
615+
throw new CREFormatException("Binary numbers must contain at most 64 digits, but \"" + val + "\" was found.", t);
616+
} else if(val.length() == 64 + 2) {
617+
longVal = (Long.parseLong(val.substring(2, 34), 2) << 32) | Long.parseLong(val.substring(34, 66), 2);
618+
} else {
619+
longVal = Long.parseLong(val.substring(2), 2);
620+
}
621+
return new CInt(longVal, t);
604622
}
605623
if(INVALID_OCTAL.matcher(val).matches()) {
606624
throw new CREFormatException("Octal numbers must only contain digits 0-7, but \"" + val + "\" was found.", t);
607625
}
608626
if(VALID_OCTAL.matcher(val).matches()) {
609-
return new CInt(Long.parseLong(val.substring(2), 8), t);
627+
628+
// Parse octal number. Special handling for 8-digit numbers to support setting all 64 bits of the value.
629+
long longVal;
630+
if(val.length() > 22 + 2) {
631+
throw new CREFormatException("Octal numbers must contain at most 22 digits, but \"" + val + "\" was found.", t);
632+
} else if(val.length() == 22 + 2) {
633+
if(val.charAt(2) != '1') {
634+
throw new CREFormatException("Octal number exceeds maximum 64-bit value 0o1777777777777777777777. Found \"" + val + "\".", t);
635+
}
636+
longVal = Long.parseLong(val.substring(3), 8) | (1L << 63);
637+
} else {
638+
longVal = Long.parseLong(val.substring(2), 8);
639+
}
640+
return new CInt(longVal, t);
610641
}
611642
if(INVALID_DECIMAL.matcher(val).matches()) {
612643
throw new CREFormatException("Decimal numbers must only contain digits, but \"" + val + "\" was found.", t);

src/test/java/com/laytonsmith/core/TestStatic.java

+16
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,22 @@ public void testResolveConstruct() {
111111
assertTrue(Static.resolveConstruct("1.1", Target.UNKNOWN) instanceof CDouble);
112112
assertTrue(Static.resolveConstruct("astring", Target.UNKNOWN) instanceof CString);
113113
assertTrue(Static.resolveConstruct("string", Target.UNKNOWN) instanceof CClassType);
114+
assertTrue(getResolveConstructLong("0xFF") == 0xFF);
115+
assertTrue(getResolveConstructLong("0xABCDEF0123456789") == 0xABCDEF0123456789L); // All chars.
116+
assertTrue(getResolveConstructLong("0xFFAFFFFFFFF0FFFF") == 0xFFAFFFFFFFF0FFFFL);
117+
assertTrue(getResolveConstructLong("0xFFFFFFFFFFFFFFFF") == 0xFFFFFFFFFFFFFFFFL); // Max value.
118+
assertTrue(getResolveConstructLong("0b100") == 0b100);
119+
assertTrue(getResolveConstructLong("0b1111011111111011111111111011111111111111111111110111111111111110")
120+
== 0b1111011111111011111111111011111111111111111111110111111111111110L);
121+
assertTrue(getResolveConstructLong("0b1111111111111111111111111111111111111111111111111111111111111111")
122+
== 0b1111111111111111111111111111111111111111111111111111111111111111L); // Max value.
123+
assertTrue(getResolveConstructLong("0o76543210") == 076543210L); // All chars.
124+
assertTrue(getResolveConstructLong("0o1737745677477125767277") == 01737745677477125767277L);
125+
assertTrue(getResolveConstructLong("0o1777777777777777777777") == 01777777777777777777777L); // Max value.
126+
}
127+
128+
private static long getResolveConstructLong(String val) {
129+
return ((CInt) Static.resolveConstruct(val, Target.UNKNOWN)).getInt();
114130
}
115131

116132
}

0 commit comments

Comments
 (0)