mirror of
https://github.com/Anuken/Mindustry.git
synced 2026-09-22 13:01:12 +03:00
Improve hex and binary literal parses (#12678)
* Improve hex and binary literal parses * Moved the specialized unsigned long parsing routine from Strings directly to LAssembler
This commit is contained in:
@@ -11,9 +11,6 @@ import mindustry.logic.LExecutor.*;
|
||||
public class LAssembler{
|
||||
public static ObjectMap<String, Func<String[], LStatement>> customParsers = new ObjectMap<>();
|
||||
|
||||
private static final long invalidNumNegative = Long.MIN_VALUE;
|
||||
private static final long invalidNumPositive = Long.MAX_VALUE;
|
||||
|
||||
public boolean privileged;
|
||||
/** Maps names to variable. */
|
||||
public OrderedMap<String, LVar> vars = new OrderedMap<>();
|
||||
@@ -110,23 +107,48 @@ public class LAssembler{
|
||||
}
|
||||
|
||||
double parseDouble(String symbol){
|
||||
//fail fast for obvious non-numbers
|
||||
if(symbol.isEmpty() || !isNumStart(symbol.charAt(0))) return Double.NaN;
|
||||
|
||||
//parse hex/binary syntax
|
||||
if(symbol.startsWith("0b")) return parseLong(false, symbol, 2, 2, symbol.length());
|
||||
if(symbol.startsWith("+0b")) return parseLong(false, symbol, 2, 3, symbol.length());
|
||||
if(symbol.startsWith("-0b")) return parseLong(true,symbol, 2, 3, symbol.length());
|
||||
if(symbol.startsWith("0x")) return parseLong(false,symbol, 16, 2, symbol.length());
|
||||
if(symbol.startsWith("+0x")) return parseLong(false,symbol, 16, 3, symbol.length());
|
||||
if(symbol.startsWith("-0x")) return parseLong(true,symbol, 16, 3, symbol.length());
|
||||
if(symbol.startsWith("0b")) return parseHexOrBin(false, symbol, true, 2);
|
||||
if(symbol.startsWith("+0b")) return parseHexOrBin(false, symbol, true, 3);
|
||||
if(symbol.startsWith("-0b")) return parseHexOrBin(true, symbol, true, 3);
|
||||
if(symbol.startsWith("0x")) return parseHexOrBin(false, symbol, false, 2);
|
||||
if(symbol.startsWith("+0x")) return parseHexOrBin(false, symbol, false, 3);
|
||||
if(symbol.startsWith("-0x")) return parseHexOrBin(true, symbol, false, 3);
|
||||
if(symbol.startsWith("%[") && symbol.endsWith("]") && symbol.length() > 3) return parseNamedColor(symbol);
|
||||
if(symbol.startsWith("%") && (symbol.length() == 7 || symbol.length() == 9)) return parseColor(symbol);
|
||||
|
||||
return Strings.parseDouble(symbol, Double.NaN);
|
||||
}
|
||||
|
||||
double parseLong(boolean negative, String s, int radix, int start, int end) {
|
||||
long usedInvalidNum = negative ? invalidNumPositive : invalidNumNegative;
|
||||
long l = Strings.parseLong(s, radix, start, end, usedInvalidNum);
|
||||
return l == usedInvalidNum ? Double.NaN : negative ? -l : l;
|
||||
boolean isNumStart(char c){
|
||||
//note that 'e10' isn't a valid number; '%ffffff' is. Hex numbers start with '0x'.
|
||||
return c >= '0' && c <= '9' || c == '.' || c == '-' || c == '+' || c == '%';
|
||||
}
|
||||
|
||||
//parses *unsigned* hex or bin number, including negative ones (0xffffffffffffffff as -1)
|
||||
//detects overflow by input length and uses bit manipulation to avoid signed arithmetics
|
||||
double parseHexOrBin(boolean negative, String s, boolean binary, int offset){
|
||||
int end = s.length();
|
||||
if(offset >= end) return Double.NaN;
|
||||
|
||||
int pos = offset;
|
||||
while(pos < end && s.charAt(pos) == '0') pos ++; //skip leading zeros to avoid incorrect overflow detection
|
||||
|
||||
int shift = binary ? 1 : 4;
|
||||
if(end - pos > 64 / shift) return Double.NaN;
|
||||
|
||||
long acc = 0;
|
||||
int radix = 1 << shift;
|
||||
while(pos < end){
|
||||
int digit = Character.digit(s.charAt(pos), radix);
|
||||
if(digit < 0) return Double.NaN;
|
||||
acc = acc << shift | digit;
|
||||
pos ++;
|
||||
}
|
||||
return negative ? -acc : acc;
|
||||
}
|
||||
|
||||
double parseColor(String symbol){
|
||||
@@ -178,4 +200,4 @@ public class LAssembler{
|
||||
return vars.get(name);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user