SnbtGrammar.java
net.minecraft.nbt.SnbtGrammar
信息
- 全限定名:net.minecraft.nbt.SnbtGrammar
- 类型:public class
- 包:net.minecraft.nbt
- 源码路径:src/main/java/net/minecraft/nbt/SnbtGrammar.java
- 起始行号:L42
- 职责:
TODO
字段/常量
-
ERROR_NUMBER_PARSE_FAILURE- 类型:
DynamicCommandExceptionType - 修饰符:
private static final - 源码定位:
L43 - 说明:
TODO
- 类型:
-
ERROR_EXPECTED_HEX_ESCAPE- 类型:
DynamicCommandExceptionType - 修饰符:
private static final - 源码定位:
L46 - 说明:
TODO
- 类型:
-
ERROR_INVALID_CODEPOINT- 类型:
DynamicCommandExceptionType - 修饰符:
private static final - 源码定位:
L49 - 说明:
TODO
- 类型:
-
ERROR_NO_SUCH_OPERATION- 类型:
DynamicCommandExceptionType - 修饰符:
private static final - 源码定位:
L52 - 说明:
TODO
- 类型:
-
ERROR_EXPECTED_INTEGER_TYPE- 类型:
DelayedException<CommandSyntaxException> - 修饰符:
private static final - 源码定位:
L55 - 说明:
TODO
- 类型:
-
ERROR_EXPECTED_FLOAT_TYPE- 类型:
DelayedException<CommandSyntaxException> - 修饰符:
private static final - 源码定位:
L58 - 说明:
TODO
- 类型:
-
ERROR_EXPECTED_NON_NEGATIVE_NUMBER- 类型:
DelayedException<CommandSyntaxException> - 修饰符:
private static final - 源码定位:
L61 - 说明:
TODO
- 类型:
-
ERROR_INVALID_CHARACTER_NAME- 类型:
DelayedException<CommandSyntaxException> - 修饰符:
private static final - 源码定位:
L64 - 说明:
TODO
- 类型:
-
ERROR_INVALID_ARRAY_ELEMENT_TYPE- 类型:
DelayedException<CommandSyntaxException> - 修饰符:
private static final - 源码定位:
L67 - 说明:
TODO
- 类型:
-
ERROR_INVALID_UNQUOTED_START- 类型:
DelayedException<CommandSyntaxException> - 修饰符:
private static final - 源码定位:
L70 - 说明:
TODO
- 类型:
-
ERROR_EXPECTED_UNQUOTED_STRING- 类型:
DelayedException<CommandSyntaxException> - 修饰符:
private static final - 源码定位:
L73 - 说明:
TODO
- 类型:
-
ERROR_INVALID_STRING_CONTENTS- 类型:
DelayedException<CommandSyntaxException> - 修饰符:
private static final - 源码定位:
L76 - 说明:
TODO
- 类型:
-
ERROR_EXPECTED_BINARY_NUMERAL- 类型:
DelayedException<CommandSyntaxException> - 修饰符:
private static final - 源码定位:
L79 - 说明:
TODO
- 类型:
-
ERROR_UNDESCORE_NOT_ALLOWED- 类型:
DelayedException<CommandSyntaxException> - 修饰符:
private static final - 源码定位:
L82 - 说明:
TODO
- 类型:
-
ERROR_EXPECTED_DECIMAL_NUMERAL- 类型:
DelayedException<CommandSyntaxException> - 修饰符:
private static final - 源码定位:
L85 - 说明:
TODO
- 类型:
-
ERROR_EXPECTED_HEX_NUMERAL- 类型:
DelayedException<CommandSyntaxException> - 修饰符:
private static final - 源码定位:
L88 - 说明:
TODO
- 类型:
-
ERROR_EMPTY_KEY- 类型:
DelayedException<CommandSyntaxException> - 修饰符:
private static final - 源码定位:
L91 - 说明:
TODO
- 类型:
-
ERROR_LEADING_ZERO_NOT_ALLOWED- 类型:
DelayedException<CommandSyntaxException> - 修饰符:
private static final - 源码定位:
L94 - 说明:
TODO
- 类型:
-
ERROR_INFINITY_NOT_ALLOWED- 类型:
DelayedException<CommandSyntaxException> - 修饰符:
private static final - 源码定位:
L97 - 说明:
TODO
- 类型:
-
HEX_ESCAPE- 类型:
HexFormat - 修饰符:
private static final - 源码定位:
L100 - 说明:
TODO
- 类型:
-
BINARY_NUMERAL- 类型:
NumberRunParseRule - 修饰符:
private static final protected default - 源码定位:
L101 - 说明:
TODO
- 类型:
-
DECIMAL_NUMERAL- 类型:
NumberRunParseRule - 修饰符:
private static final protected default - 源码定位:
L110 - 说明:
TODO
- 类型:
-
HEX_NUMERAL- 类型:
NumberRunParseRule - 修饰符:
private static final protected default - 源码定位:
L119 - 说明:
TODO
- 类型:
-
PLAIN_STRING_CHUNK- 类型:
GreedyPredicateParseRule - 修饰符:
private static final protected default - 源码定位:
L128 - 说明:
TODO
- 类型:
-
NUMBER_LOOKEAHEAD- 类型:
StringReaderTerms.TerminalCharacters - 修饰符:
private static final protected - 源码定位:
L137 - 说明:
TODO
- 类型:
-
UNICODE_NAME- 类型:
Pattern - 修饰符:
private static final - 源码定位:
L143 - 说明:
TODO
- 类型:
内部类/嵌套类型
-
net.minecraft.nbt.SnbtGrammar.ArrayPrefix- 类型:
enum - 修饰符:
private static - 源码定位:
L705 - 说明:
TODO
- 类型:
-
net.minecraft.nbt.SnbtGrammar.Base- 类型:
enum - 修饰符:
private static - 源码定位:
L811 - 说明:
TODO
- 类型:
-
net.minecraft.nbt.SnbtGrammar.IntegerLiteral- 类型:
record - 修饰符:
private - 源码定位:
L817 - 说明:
TODO
- 类型:
-
net.minecraft.nbt.SnbtGrammar.IntegerSuffix- 类型:
record - 修饰符:
private - 源码定位:
L891 - 说明:
TODO
- 类型:
-
net.minecraft.nbt.SnbtGrammar.Sign- 类型:
enum - 修饰符:
private static - 源码定位:
L895 - 说明:
TODO
- 类型:
-
net.minecraft.nbt.SnbtGrammar.Signed- 类型:
record - 修饰符:
private - 源码定位:
L906 - 说明:
TODO
- 类型:
-
net.minecraft.nbt.SnbtGrammar.SignedPrefix- 类型:
enum - 修饰符:
private static - 源码定位:
L909 - 说明:
TODO
- 类型:
-
net.minecraft.nbt.SnbtGrammar.SimpleHexLiteralParseRule- 类型:
class - 修饰符:
private static - 源码定位:
L914 - 说明:
TODO
- 类型:
-
net.minecraft.nbt.SnbtGrammar.TypeSuffix- 类型:
enum - 修饰符:
private static - 源码定位:
L928 - 说明:
TODO
- 类型:
构造器
- 无
方法
下面的方法块按源码顺序生成。
private static DelayedException<CommandSyntaxException> createNumberParseError(NumberFormatException ex) @ L145
- 方法名:createNumberParseError
- 源码定位:L145
- 返回类型:DelayedException
- 修饰符:private static
参数:
- ex: NumberFormatException
说明:
TODO
public static String escapeControlCharacters(char c) @ L149
- 方法名:escapeControlCharacters
- 源码定位:L149
- 返回类型:String
- 修饰符:public static
参数:
- c: char
说明:
TODO
private static boolean isAllowedToStartUnquotedString(char c) @ L160
- 方法名:isAllowedToStartUnquotedString
- 源码定位:L160
- 返回类型:boolean
- 修饰符:private static
参数:
- c: char
说明:
TODO
private static boolean canStartNumber(char c) @ L164
- 方法名:canStartNumber
- 源码定位:L164
- 返回类型:boolean
- 修饰符:private static
参数:
- c: char
说明:
TODO
private static boolean needsUnderscoreRemoval(String contents) @ L171
- 方法名:needsUnderscoreRemoval
- 源码定位:L171
- 返回类型:boolean
- 修饰符:private static
参数:
- contents: String
说明:
TODO
private static void cleanAndAppend(StringBuilder output, String contents) @ L175
- 方法名:cleanAndAppend
- 源码定位:L175
- 返回类型:void
- 修饰符:private static
参数:
- output: StringBuilder
- contents: String
说明:
TODO
private static void cleanAndAppend(StringBuilder output, String contents, boolean needsUnderscoreRemoval) @ L179
- 方法名:cleanAndAppend
- 源码定位:L179
- 返回类型:void
- 修饰符:private static
参数:
- output: StringBuilder
- contents: String
- needsUnderscoreRemoval: boolean
说明:
TODO
private static short parseUnsignedShort(String string, int radix) @ L191
- 方法名:parseUnsignedShort
- 源码定位:L191
- 返回类型:short
- 修饰符:private static
参数:
- string: String
- radix: int
说明:
TODO
private static <T> T createFloat(DynamicOps<T> ops, SnbtGrammar.Sign sign, String whole, String fraction, SnbtGrammar.Signed<String> exponent, SnbtGrammar.TypeSuffix typeSuffix, ParseState<?> state) @ L200
- 方法名:createFloat
- 源码定位:L200
- 返回类型:
T - 修饰符:private static
参数:
- ops: DynamicOps
- sign: SnbtGrammar.Sign
- whole: String
- fraction: String
- exponent: SnbtGrammar.Signed
- typeSuffix: SnbtGrammar.TypeSuffix
- state: ParseState<?>
说明:
TODO
private static <T> T convertFloat(DynamicOps<T> ops, ParseState<?> state, String contents) @ L244
- 方法名:convertFloat
- 源码定位:L244
- 返回类型:
T - 修饰符:private static
参数:
- ops: DynamicOps
- state: ParseState<?>
- contents: String
说明:
TODO
private static <T> T convertDouble(DynamicOps<T> ops, ParseState<?> state, String contents) @ L254
- 方法名:convertDouble
- 源码定位:L254
- 返回类型:
T - 修饰符:private static
参数:
- ops: DynamicOps
- state: ParseState<?>
- contents: String
说明:
TODO
private static String joinList(List<String> list) @ L264
- 方法名:joinList
- 源码定位:L264
- 返回类型:String
- 修饰符:private static
参数:
- list: List
说明:
TODO
public static <T> Grammar<T> createParser(DynamicOps<T> ops) @ L272
- 方法名:createParser
- 源码定位:L272
- 返回类型:
Grammar - 修饰符:public static
参数:
- ops: DynamicOps
说明:
TODO
代码
public class SnbtGrammar {
private static final DynamicCommandExceptionType ERROR_NUMBER_PARSE_FAILURE = new DynamicCommandExceptionType(
message -> Component.translatableEscape("snbt.parser.number_parse_failure", message)
);
private static final DynamicCommandExceptionType ERROR_EXPECTED_HEX_ESCAPE = new DynamicCommandExceptionType(
length -> Component.translatableEscape("snbt.parser.expected_hex_escape", length)
);
private static final DynamicCommandExceptionType ERROR_INVALID_CODEPOINT = new DynamicCommandExceptionType(
codepoint -> Component.translatableEscape("snbt.parser.invalid_codepoint", codepoint)
);
private static final DynamicCommandExceptionType ERROR_NO_SUCH_OPERATION = new DynamicCommandExceptionType(
operation -> Component.translatableEscape("snbt.parser.no_such_operation", operation)
);
private static final DelayedException<CommandSyntaxException> ERROR_EXPECTED_INTEGER_TYPE = DelayedException.create(
new SimpleCommandExceptionType(Component.translatable("snbt.parser.expected_integer_type"))
);
private static final DelayedException<CommandSyntaxException> ERROR_EXPECTED_FLOAT_TYPE = DelayedException.create(
new SimpleCommandExceptionType(Component.translatable("snbt.parser.expected_float_type"))
);
private static final DelayedException<CommandSyntaxException> ERROR_EXPECTED_NON_NEGATIVE_NUMBER = DelayedException.create(
new SimpleCommandExceptionType(Component.translatable("snbt.parser.expected_non_negative_number"))
);
private static final DelayedException<CommandSyntaxException> ERROR_INVALID_CHARACTER_NAME = DelayedException.create(
new SimpleCommandExceptionType(Component.translatable("snbt.parser.invalid_character_name"))
);
private static final DelayedException<CommandSyntaxException> ERROR_INVALID_ARRAY_ELEMENT_TYPE = DelayedException.create(
new SimpleCommandExceptionType(Component.translatable("snbt.parser.invalid_array_element_type"))
);
private static final DelayedException<CommandSyntaxException> ERROR_INVALID_UNQUOTED_START = DelayedException.create(
new SimpleCommandExceptionType(Component.translatable("snbt.parser.invalid_unquoted_start"))
);
private static final DelayedException<CommandSyntaxException> ERROR_EXPECTED_UNQUOTED_STRING = DelayedException.create(
new SimpleCommandExceptionType(Component.translatable("snbt.parser.expected_unquoted_string"))
);
private static final DelayedException<CommandSyntaxException> ERROR_INVALID_STRING_CONTENTS = DelayedException.create(
new SimpleCommandExceptionType(Component.translatable("snbt.parser.invalid_string_contents"))
);
private static final DelayedException<CommandSyntaxException> ERROR_EXPECTED_BINARY_NUMERAL = DelayedException.create(
new SimpleCommandExceptionType(Component.translatable("snbt.parser.expected_binary_numeral"))
);
private static final DelayedException<CommandSyntaxException> ERROR_UNDESCORE_NOT_ALLOWED = DelayedException.create(
new SimpleCommandExceptionType(Component.translatable("snbt.parser.underscore_not_allowed"))
);
private static final DelayedException<CommandSyntaxException> ERROR_EXPECTED_DECIMAL_NUMERAL = DelayedException.create(
new SimpleCommandExceptionType(Component.translatable("snbt.parser.expected_decimal_numeral"))
);
private static final DelayedException<CommandSyntaxException> ERROR_EXPECTED_HEX_NUMERAL = DelayedException.create(
new SimpleCommandExceptionType(Component.translatable("snbt.parser.expected_hex_numeral"))
);
private static final DelayedException<CommandSyntaxException> ERROR_EMPTY_KEY = DelayedException.create(
new SimpleCommandExceptionType(Component.translatable("snbt.parser.empty_key"))
);
private static final DelayedException<CommandSyntaxException> ERROR_LEADING_ZERO_NOT_ALLOWED = DelayedException.create(
new SimpleCommandExceptionType(Component.translatable("snbt.parser.leading_zero_not_allowed"))
);
private static final DelayedException<CommandSyntaxException> ERROR_INFINITY_NOT_ALLOWED = DelayedException.create(
new SimpleCommandExceptionType(Component.translatable("snbt.parser.infinity_not_allowed"))
);
private static final HexFormat HEX_ESCAPE = HexFormat.of().withUpperCase();
private static final NumberRunParseRule BINARY_NUMERAL = new NumberRunParseRule(ERROR_EXPECTED_BINARY_NUMERAL, ERROR_UNDESCORE_NOT_ALLOWED) {
@Override
protected boolean isAccepted(char c) {
return switch (c) {
case '0', '1', '_' -> true;
default -> false;
};
}
};
private static final NumberRunParseRule DECIMAL_NUMERAL = new NumberRunParseRule(ERROR_EXPECTED_DECIMAL_NUMERAL, ERROR_UNDESCORE_NOT_ALLOWED) {
@Override
protected boolean isAccepted(char c) {
return switch (c) {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '_' -> true;
default -> false;
};
}
};
private static final NumberRunParseRule HEX_NUMERAL = new NumberRunParseRule(ERROR_EXPECTED_HEX_NUMERAL, ERROR_UNDESCORE_NOT_ALLOWED) {
@Override
protected boolean isAccepted(char c) {
return switch (c) {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', '_', 'a', 'b', 'c', 'd', 'e', 'f' -> true;
default -> false;
};
}
};
private static final GreedyPredicateParseRule PLAIN_STRING_CHUNK = new GreedyPredicateParseRule(1, ERROR_INVALID_STRING_CONTENTS) {
@Override
protected boolean isAccepted(char c) {
return switch (c) {
case '"', '\'', '\\' -> false;
default -> true;
};
}
};
private static final StringReaderTerms.TerminalCharacters NUMBER_LOOKEAHEAD = new StringReaderTerms.TerminalCharacters(CharList.of()) {
@Override
protected boolean isAccepted(char c) {
return SnbtGrammar.canStartNumber(c);
}
};
private static final Pattern UNICODE_NAME = Pattern.compile("[-a-zA-Z0-9 ]+");
private static DelayedException<CommandSyntaxException> createNumberParseError(NumberFormatException ex) {
return DelayedException.create(ERROR_NUMBER_PARSE_FAILURE, ex.getMessage());
}
public static @Nullable String escapeControlCharacters(char c) {
return switch (c) {
case '\b' -> "b";
case '\t' -> "t";
case '\n' -> "n";
default -> c < ' ' ? "x" + HEX_ESCAPE.toHexDigits((byte)c) : null;
case '\f' -> "f";
case '\r' -> "r";
};
}
private static boolean isAllowedToStartUnquotedString(char c) {
return !canStartNumber(c);
}
private static boolean canStartNumber(char c) {
return switch (c) {
case '+', '-', '.', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' -> true;
default -> false;
};
}
private static boolean needsUnderscoreRemoval(String contents) {
return contents.indexOf(95) != -1;
}
private static void cleanAndAppend(StringBuilder output, String contents) {
cleanAndAppend(output, contents, needsUnderscoreRemoval(contents));
}
private static void cleanAndAppend(StringBuilder output, String contents, boolean needsUnderscoreRemoval) {
if (needsUnderscoreRemoval) {
for (char c : contents.toCharArray()) {
if (c != '_') {
output.append(c);
}
}
} else {
output.append(contents);
}
}
private static short parseUnsignedShort(String string, int radix) {
int parse = Integer.parseInt(string, radix);
if (parse >> 16 == 0) {
return (short)parse;
} else {
throw new NumberFormatException("out of range: " + parse);
}
}
private static <T> @Nullable T createFloat(
DynamicOps<T> ops,
SnbtGrammar.Sign sign,
@Nullable String whole,
@Nullable String fraction,
SnbtGrammar.@Nullable Signed<String> exponent,
SnbtGrammar.@Nullable TypeSuffix typeSuffix,
ParseState<?> state
) {
StringBuilder result = new StringBuilder();
sign.append(result);
if (whole != null) {
cleanAndAppend(result, whole);
}
if (fraction != null) {
result.append('.');
cleanAndAppend(result, fraction);
}
if (exponent != null) {
result.append('e');
exponent.sign().append(result);
cleanAndAppend(result, exponent.value);
}
try {
String contents = result.toString();
return (T)(switch (typeSuffix) {
case null -> convertDouble(ops, state, contents);
case FLOAT -> convertFloat(ops, state, contents);
case DOUBLE -> convertDouble(ops, state, contents);
default -> {
state.errorCollector().store(state.mark(), ERROR_EXPECTED_FLOAT_TYPE);
yield null;
}
});
} catch (NumberFormatException var11) {
state.errorCollector().store(state.mark(), createNumberParseError(var11));
return null;
}
}
private static <T> @Nullable T convertFloat(DynamicOps<T> ops, ParseState<?> state, String contents) {
float value = Float.parseFloat(contents);
if (!Float.isFinite(value)) {
state.errorCollector().store(state.mark(), ERROR_INFINITY_NOT_ALLOWED);
return null;
} else {
return ops.createFloat(value);
}
}
private static <T> @Nullable T convertDouble(DynamicOps<T> ops, ParseState<?> state, String contents) {
double value = Double.parseDouble(contents);
if (!Double.isFinite(value)) {
state.errorCollector().store(state.mark(), ERROR_INFINITY_NOT_ALLOWED);
return null;
} else {
return ops.createDouble(value);
}
}
private static String joinList(List<String> list) {
return switch (list.size()) {
case 0 -> "";
case 1 -> (String)list.getFirst();
default -> String.join("", list);
};
}
public static <T> Grammar<T> createParser(DynamicOps<T> ops) {
T trueValue = ops.createBoolean(true);
T falseValue = ops.createBoolean(false);
T emptyMapValue = ops.emptyMap();
T emptyList = ops.emptyList();
Dictionary<StringReader> rules = new Dictionary<>();
Atom<SnbtGrammar.Sign> sign = Atom.of("sign");
rules.put(
sign,
Term.alternative(
Term.sequence(StringReaderTerms.character('+'), Term.marker(sign, SnbtGrammar.Sign.PLUS)),
Term.sequence(StringReaderTerms.character('-'), Term.marker(sign, SnbtGrammar.Sign.MINUS))
),
scope -> scope.getOrThrow(sign)
);
Atom<SnbtGrammar.IntegerSuffix> integerSuffix = Atom.of("integer_suffix");
rules.put(
integerSuffix,
Term.alternative(
Term.sequence(
StringReaderTerms.characters('u', 'U'),
Term.alternative(
Term.sequence(
StringReaderTerms.characters('b', 'B'),
Term.marker(integerSuffix, new SnbtGrammar.IntegerSuffix(SnbtGrammar.SignedPrefix.UNSIGNED, SnbtGrammar.TypeSuffix.BYTE))
),
Term.sequence(
StringReaderTerms.characters('s', 'S'),
Term.marker(integerSuffix, new SnbtGrammar.IntegerSuffix(SnbtGrammar.SignedPrefix.UNSIGNED, SnbtGrammar.TypeSuffix.SHORT))
),
Term.sequence(
StringReaderTerms.characters('i', 'I'),
Term.marker(integerSuffix, new SnbtGrammar.IntegerSuffix(SnbtGrammar.SignedPrefix.UNSIGNED, SnbtGrammar.TypeSuffix.INT))
),
Term.sequence(
StringReaderTerms.characters('l', 'L'),
Term.marker(integerSuffix, new SnbtGrammar.IntegerSuffix(SnbtGrammar.SignedPrefix.UNSIGNED, SnbtGrammar.TypeSuffix.LONG))
)
)
),
Term.sequence(
StringReaderTerms.characters('s', 'S'),
Term.alternative(
Term.sequence(
StringReaderTerms.characters('b', 'B'),
Term.marker(integerSuffix, new SnbtGrammar.IntegerSuffix(SnbtGrammar.SignedPrefix.SIGNED, SnbtGrammar.TypeSuffix.BYTE))
),
Term.sequence(
StringReaderTerms.characters('s', 'S'),
Term.marker(integerSuffix, new SnbtGrammar.IntegerSuffix(SnbtGrammar.SignedPrefix.SIGNED, SnbtGrammar.TypeSuffix.SHORT))
),
Term.sequence(
StringReaderTerms.characters('i', 'I'),
Term.marker(integerSuffix, new SnbtGrammar.IntegerSuffix(SnbtGrammar.SignedPrefix.SIGNED, SnbtGrammar.TypeSuffix.INT))
),
Term.sequence(
StringReaderTerms.characters('l', 'L'),
Term.marker(integerSuffix, new SnbtGrammar.IntegerSuffix(SnbtGrammar.SignedPrefix.SIGNED, SnbtGrammar.TypeSuffix.LONG))
)
)
),
Term.sequence(
StringReaderTerms.characters('b', 'B'), Term.marker(integerSuffix, new SnbtGrammar.IntegerSuffix(null, SnbtGrammar.TypeSuffix.BYTE))
),
Term.sequence(
StringReaderTerms.characters('s', 'S'), Term.marker(integerSuffix, new SnbtGrammar.IntegerSuffix(null, SnbtGrammar.TypeSuffix.SHORT))
),
Term.sequence(
StringReaderTerms.characters('i', 'I'), Term.marker(integerSuffix, new SnbtGrammar.IntegerSuffix(null, SnbtGrammar.TypeSuffix.INT))
),
Term.sequence(
StringReaderTerms.characters('l', 'L'), Term.marker(integerSuffix, new SnbtGrammar.IntegerSuffix(null, SnbtGrammar.TypeSuffix.LONG))
)
),
scope -> scope.getOrThrow(integerSuffix)
);
Atom<String> binaryNumeral = Atom.of("binary_numeral");
rules.put(binaryNumeral, BINARY_NUMERAL);
Atom<String> decimalNumeral = Atom.of("decimal_numeral");
rules.put(decimalNumeral, DECIMAL_NUMERAL);
Atom<String> hexNumeral = Atom.of("hex_numeral");
rules.put(hexNumeral, HEX_NUMERAL);
Atom<SnbtGrammar.IntegerLiteral> integerLiteral = Atom.of("integer_literal");
NamedRule<StringReader, SnbtGrammar.IntegerLiteral> integerLiteralRule = rules.put(
integerLiteral,
Term.sequence(
Term.optional(rules.named(sign)),
Term.alternative(
Term.sequence(
StringReaderTerms.character('0'),
Term.cut(),
Term.alternative(
Term.sequence(StringReaderTerms.characters('x', 'X'), Term.cut(), rules.named(hexNumeral)),
Term.sequence(StringReaderTerms.characters('b', 'B'), rules.named(binaryNumeral)),
Term.sequence(rules.named(decimalNumeral), Term.cut(), Term.fail(ERROR_LEADING_ZERO_NOT_ALLOWED)),
Term.marker(decimalNumeral, "0")
)
),
rules.named(decimalNumeral)
),
Term.optional(rules.named(integerSuffix))
),
scope -> {
SnbtGrammar.IntegerSuffix suffix = scope.getOrDefault(integerSuffix, SnbtGrammar.IntegerSuffix.EMPTY);
SnbtGrammar.Sign signValue = scope.getOrDefault(sign, SnbtGrammar.Sign.PLUS);
String decimalContents = scope.get(decimalNumeral);
if (decimalContents != null) {
return new SnbtGrammar.IntegerLiteral(signValue, SnbtGrammar.Base.DECIMAL, decimalContents, suffix);
} else {
String hexContents = scope.get(hexNumeral);
if (hexContents != null) {
return new SnbtGrammar.IntegerLiteral(signValue, SnbtGrammar.Base.HEX, hexContents, suffix);
} else {
String binaryContents = scope.getOrThrow(binaryNumeral);
return new SnbtGrammar.IntegerLiteral(signValue, SnbtGrammar.Base.BINARY, binaryContents, suffix);
}
}
}
);
Atom<SnbtGrammar.TypeSuffix> floatTypeSuffix = Atom.of("float_type_suffix");
rules.put(
floatTypeSuffix,
Term.alternative(
Term.sequence(StringReaderTerms.characters('f', 'F'), Term.marker(floatTypeSuffix, SnbtGrammar.TypeSuffix.FLOAT)),
Term.sequence(StringReaderTerms.characters('d', 'D'), Term.marker(floatTypeSuffix, SnbtGrammar.TypeSuffix.DOUBLE))
),
scope -> scope.getOrThrow(floatTypeSuffix)
);
Atom<SnbtGrammar.Signed<String>> floatExponentPart = Atom.of("float_exponent_part");
rules.put(
floatExponentPart,
Term.sequence(StringReaderTerms.characters('e', 'E'), Term.optional(rules.named(sign)), rules.named(decimalNumeral)),
scope -> new SnbtGrammar.Signed<>(scope.getOrDefault(sign, SnbtGrammar.Sign.PLUS), scope.getOrThrow(decimalNumeral))
);
Atom<String> floatWholePart = Atom.of("float_whole_part");
Atom<String> floatFractionPart = Atom.of("float_fraction_part");
Atom<T> floatLiteral = Atom.of("float_literal");
rules.putComplex(
floatLiteral,
Term.sequence(
Term.optional(rules.named(sign)),
Term.alternative(
Term.sequence(
rules.namedWithAlias(decimalNumeral, floatWholePart),
StringReaderTerms.character('.'),
Term.cut(),
Term.optional(rules.namedWithAlias(decimalNumeral, floatFractionPart)),
Term.optional(rules.named(floatExponentPart)),
Term.optional(rules.named(floatTypeSuffix))
),
Term.sequence(
StringReaderTerms.character('.'),
Term.cut(),
rules.namedWithAlias(decimalNumeral, floatFractionPart),
Term.optional(rules.named(floatExponentPart)),
Term.optional(rules.named(floatTypeSuffix))
),
Term.sequence(
rules.namedWithAlias(decimalNumeral, floatWholePart),
rules.named(floatExponentPart),
Term.cut(),
Term.optional(rules.named(floatTypeSuffix))
),
Term.sequence(
rules.namedWithAlias(decimalNumeral, floatWholePart), Term.optional(rules.named(floatExponentPart)), rules.named(floatTypeSuffix)
)
)
),
state -> {
Scope scope = state.scope();
SnbtGrammar.Sign wholeSign = scope.getOrDefault(sign, SnbtGrammar.Sign.PLUS);
String whole = scope.get(floatWholePart);
String fraction = scope.get(floatFractionPart);
SnbtGrammar.Signed<String> exponent = scope.get(floatExponentPart);
SnbtGrammar.TypeSuffix typeSuffix = scope.get(floatTypeSuffix);
return createFloat(ops, wholeSign, whole, fraction, exponent, typeSuffix, state);
}
);
Atom<String> stringHex2 = Atom.of("string_hex_2");
rules.put(stringHex2, new SnbtGrammar.SimpleHexLiteralParseRule(2));
Atom<String> stringHex4 = Atom.of("string_hex_4");
rules.put(stringHex4, new SnbtGrammar.SimpleHexLiteralParseRule(4));
Atom<String> stringHex8 = Atom.of("string_hex_8");
rules.put(stringHex8, new SnbtGrammar.SimpleHexLiteralParseRule(8));
Atom<String> stringUnicodeName = Atom.of("string_unicode_name");
rules.put(stringUnicodeName, new GreedyPatternParseRule(UNICODE_NAME, ERROR_INVALID_CHARACTER_NAME));
Atom<String> stringEscapeSequence = Atom.of("string_escape_sequence");
rules.putComplex(
stringEscapeSequence,
Term.alternative(
Term.sequence(StringReaderTerms.character('b'), Term.marker(stringEscapeSequence, "\b")),
Term.sequence(StringReaderTerms.character('s'), Term.marker(stringEscapeSequence, " ")),
Term.sequence(StringReaderTerms.character('t'), Term.marker(stringEscapeSequence, "\t")),
Term.sequence(StringReaderTerms.character('n'), Term.marker(stringEscapeSequence, "\n")),
Term.sequence(StringReaderTerms.character('f'), Term.marker(stringEscapeSequence, "\f")),
Term.sequence(StringReaderTerms.character('r'), Term.marker(stringEscapeSequence, "\r")),
Term.sequence(StringReaderTerms.character('\\'), Term.marker(stringEscapeSequence, "\\")),
Term.sequence(StringReaderTerms.character('\''), Term.marker(stringEscapeSequence, "'")),
Term.sequence(StringReaderTerms.character('"'), Term.marker(stringEscapeSequence, "\"")),
Term.sequence(StringReaderTerms.character('x'), rules.named(stringHex2)),
Term.sequence(StringReaderTerms.character('u'), rules.named(stringHex4)),
Term.sequence(StringReaderTerms.character('U'), rules.named(stringHex8)),
Term.sequence(
StringReaderTerms.character('N'), StringReaderTerms.character('{'), rules.named(stringUnicodeName), StringReaderTerms.character('}')
)
),
state -> {
Scope scope = state.scope();
String plainEscape = scope.getAny(stringEscapeSequence);
if (plainEscape != null) {
return plainEscape;
} else {
String hexEscape = scope.getAny(stringHex2, stringHex4, stringHex8);
if (hexEscape != null) {
int codePoint = HexFormat.fromHexDigits(hexEscape);
if (!Character.isValidCodePoint(codePoint)) {
state.errorCollector()
.store(state.mark(), DelayedException.create(ERROR_INVALID_CODEPOINT, String.format(Locale.ROOT, "U+%08X", codePoint)));
return null;
} else {
return Character.toString(codePoint);
}
} else {
String character = scope.getOrThrow(stringUnicodeName);
int codePoint;
try {
codePoint = Character.codePointOf(character);
} catch (IllegalArgumentException var12x) {
state.errorCollector().store(state.mark(), ERROR_INVALID_CHARACTER_NAME);
return null;
}
return Character.toString(codePoint);
}
}
}
);
Atom<String> stringPlainContents = Atom.of("string_plain_contents");
rules.put(stringPlainContents, PLAIN_STRING_CHUNK);
Atom<List<String>> stringChunks = Atom.of("string_chunks");
Atom<String> stringContents = Atom.of("string_contents");
Atom<String> singleQuotedStringChunk = Atom.of("single_quoted_string_chunk");
NamedRule<StringReader, String> singleQuotedStringChunkRule = rules.put(
singleQuotedStringChunk,
Term.alternative(
rules.namedWithAlias(stringPlainContents, stringContents),
Term.sequence(StringReaderTerms.character('\\'), rules.namedWithAlias(stringEscapeSequence, stringContents)),
Term.sequence(StringReaderTerms.character('"'), Term.marker(stringContents, "\""))
),
scope -> scope.getOrThrow(stringContents)
);
Atom<String> singleQuotedStringContents = Atom.of("single_quoted_string_contents");
rules.put(singleQuotedStringContents, Term.repeated(singleQuotedStringChunkRule, stringChunks), scope -> joinList(scope.getOrThrow(stringChunks)));
Atom<String> doubleQuotedStringChunk = Atom.of("double_quoted_string_chunk");
NamedRule<StringReader, String> doubleQuotedStringChunkRule = rules.put(
doubleQuotedStringChunk,
Term.alternative(
rules.namedWithAlias(stringPlainContents, stringContents),
Term.sequence(StringReaderTerms.character('\\'), rules.namedWithAlias(stringEscapeSequence, stringContents)),
Term.sequence(StringReaderTerms.character('\''), Term.marker(stringContents, "'"))
),
scope -> scope.getOrThrow(stringContents)
);
Atom<String> doubleQuotedStringContents = Atom.of("double_quoted_string_contents");
rules.put(doubleQuotedStringContents, Term.repeated(doubleQuotedStringChunkRule, stringChunks), scope -> joinList(scope.getOrThrow(stringChunks)));
Atom<String> quotedStringLiteral = Atom.of("quoted_string_literal");
rules.put(
quotedStringLiteral,
Term.alternative(
Term.sequence(
StringReaderTerms.character('"'),
Term.cut(),
Term.optional(rules.namedWithAlias(doubleQuotedStringContents, stringContents)),
StringReaderTerms.character('"')
),
Term.sequence(
StringReaderTerms.character('\''),
Term.optional(rules.namedWithAlias(singleQuotedStringContents, stringContents)),
StringReaderTerms.character('\'')
)
),
scope -> scope.getOrThrow(stringContents)
);
Atom<String> unquotedString = Atom.of("unquoted_string");
rules.put(unquotedString, new UnquotedStringParseRule(1, ERROR_EXPECTED_UNQUOTED_STRING));
Atom<T> literal = Atom.of("literal");
Atom<List<T>> argumentList = Atom.of("arguments");
rules.put(
argumentList,
Term.repeatedWithTrailingSeparator(rules.forward(literal), argumentList, StringReaderTerms.character(',')),
scope -> scope.getOrThrow(argumentList)
);
Atom<T> unquotedStringOrBuiltIn = Atom.of("unquoted_string_or_builtin");
rules.putComplex(
unquotedStringOrBuiltIn,
Term.sequence(
rules.named(unquotedString),
Term.optional(Term.sequence(StringReaderTerms.character('('), rules.named(argumentList), StringReaderTerms.character(')')))
),
state -> {
Scope scope = state.scope();
String contents = scope.getOrThrow(unquotedString);
if (!contents.isEmpty() && isAllowedToStartUnquotedString(contents.charAt(0))) {
List<T> arguments = scope.get(argumentList);
if (arguments != null) {
SnbtOperations.BuiltinKey key = new SnbtOperations.BuiltinKey(contents, arguments.size());
SnbtOperations.BuiltinOperation operation = SnbtOperations.BUILTIN_OPERATIONS.get(key);
if (operation != null) {
return operation.run(ops, arguments, state);
} else {
state.errorCollector().store(state.mark(), DelayedException.create(ERROR_NO_SUCH_OPERATION, key.toString()));
return null;
}
} else if (contents.equalsIgnoreCase("true")) {
return trueValue;
} else {
return contents.equalsIgnoreCase("false") ? falseValue : ops.createString(contents);
}
} else {
state.errorCollector().store(state.mark(), SnbtOperations.BUILTIN_IDS, ERROR_INVALID_UNQUOTED_START);
return null;
}
}
);
Atom<String> mapKey = Atom.of("map_key");
rules.put(
mapKey,
Term.alternative(rules.named(quotedStringLiteral), rules.named(unquotedString)),
scope -> scope.getAnyOrThrow(quotedStringLiteral, unquotedString)
);
Atom<Entry<String, T>> mapEntry = Atom.of("map_entry");
NamedRule<StringReader, Entry<String, T>> mapEntryRule = rules.putComplex(
mapEntry, Term.sequence(rules.named(mapKey), StringReaderTerms.character(':'), rules.named(literal)), state -> {
Scope scope = state.scope();
String key = scope.getOrThrow(mapKey);
if (key.isEmpty()) {
state.errorCollector().store(state.mark(), ERROR_EMPTY_KEY);
return null;
} else {
T value = scope.getOrThrow(literal);
return Map.entry(key, value);
}
}
);
Atom<List<Entry<String, T>>> mapEntries = Atom.of("map_entries");
rules.put(
mapEntries, Term.repeatedWithTrailingSeparator(mapEntryRule, mapEntries, StringReaderTerms.character(',')), scope -> scope.getOrThrow(mapEntries)
);
Atom<T> mapLiteral = Atom.of("map_literal");
rules.put(mapLiteral, Term.sequence(StringReaderTerms.character('{'), rules.named(mapEntries), StringReaderTerms.character('}')), scope -> {
List<Entry<String, T>> entries = scope.getOrThrow(mapEntries);
if (entries.isEmpty()) {
return emptyMapValue;
} else {
Builder<T, T> builder = ImmutableMap.builderWithExpectedSize(entries.size());
for (Entry<String, T> e : entries) {
builder.put(ops.createString(e.getKey()), e.getValue());
}
return ops.createMap(builder.buildKeepingLast());
}
});
Atom<List<T>> listEntries = Atom.of("list_entries");
rules.put(
listEntries,
Term.repeatedWithTrailingSeparator(rules.forward(literal), listEntries, StringReaderTerms.character(',')),
scope -> scope.getOrThrow(listEntries)
);
Atom<SnbtGrammar.ArrayPrefix> arrayPrefix = Atom.of("array_prefix");
rules.put(
arrayPrefix,
Term.alternative(
Term.sequence(StringReaderTerms.character('B'), Term.marker(arrayPrefix, SnbtGrammar.ArrayPrefix.BYTE)),
Term.sequence(StringReaderTerms.character('L'), Term.marker(arrayPrefix, SnbtGrammar.ArrayPrefix.LONG)),
Term.sequence(StringReaderTerms.character('I'), Term.marker(arrayPrefix, SnbtGrammar.ArrayPrefix.INT))
),
scope -> scope.getOrThrow(arrayPrefix)
);
Atom<List<SnbtGrammar.IntegerLiteral>> intArrayEntries = Atom.of("int_array_entries");
rules.put(
intArrayEntries,
Term.repeatedWithTrailingSeparator(integerLiteralRule, intArrayEntries, StringReaderTerms.character(',')),
scope -> scope.getOrThrow(intArrayEntries)
);
Atom<T> listLiteral = Atom.of("list_literal");
rules.putComplex(
listLiteral,
Term.sequence(
StringReaderTerms.character('['),
Term.alternative(
Term.sequence(rules.named(arrayPrefix), StringReaderTerms.character(';'), rules.named(intArrayEntries)), rules.named(listEntries)
),
StringReaderTerms.character(']')
),
state -> {
Scope scope = state.scope();
SnbtGrammar.ArrayPrefix arrayType = scope.get(arrayPrefix);
if (arrayType != null) {
List<SnbtGrammar.IntegerLiteral> entries = scope.getOrThrow(intArrayEntries);
return entries.isEmpty() ? arrayType.create(ops) : arrayType.create(ops, entries, state);
} else {
List<T> entries = scope.getOrThrow(listEntries);
return entries.isEmpty() ? emptyList : ops.createList(entries.stream());
}
}
);
NamedRule<StringReader, T> literalRule = rules.putComplex(
literal,
Term.alternative(
Term.sequence(
Term.positiveLookahead(NUMBER_LOOKEAHEAD), Term.alternative(rules.namedWithAlias(floatLiteral, literal), rules.named(integerLiteral))
),
Term.sequence(Term.positiveLookahead(StringReaderTerms.characters('"', '\'')), Term.cut(), rules.named(quotedStringLiteral)),
Term.sequence(Term.positiveLookahead(StringReaderTerms.character('{')), Term.cut(), rules.namedWithAlias(mapLiteral, literal)),
Term.sequence(Term.positiveLookahead(StringReaderTerms.character('[')), Term.cut(), rules.namedWithAlias(listLiteral, literal)),
rules.namedWithAlias(unquotedStringOrBuiltIn, literal)
),
state -> {
Scope scope = state.scope();
String quotedString = scope.get(quotedStringLiteral);
if (quotedString != null) {
return ops.createString(quotedString);
} else {
SnbtGrammar.IntegerLiteral integer = scope.get(integerLiteral);
return integer != null ? integer.create(ops, state) : scope.getOrThrow(literal);
}
}
);
return new Grammar<>(rules, literalRule);
}
private static enum ArrayPrefix {
BYTE(SnbtGrammar.TypeSuffix.BYTE) {
private static final ByteBuffer EMPTY_BUFFER = ByteBuffer.wrap(new byte[0]);
@Override
public <T> T create(DynamicOps<T> ops) {
return ops.createByteList(EMPTY_BUFFER);
}
@Override
public <T> @Nullable T create(DynamicOps<T> ops, List<SnbtGrammar.IntegerLiteral> entries, ParseState<?> state) {
ByteList result = new ByteArrayList();
for (SnbtGrammar.IntegerLiteral entry : entries) {
Number parsedNumber = this.buildNumber(entry, state);
if (parsedNumber == null) {
return null;
}
result.add(parsedNumber.byteValue());
}
return ops.createByteList(ByteBuffer.wrap(result.toByteArray()));
}
},
INT(SnbtGrammar.TypeSuffix.INT, SnbtGrammar.TypeSuffix.BYTE, SnbtGrammar.TypeSuffix.SHORT) {
@Override
public <T> T create(DynamicOps<T> ops) {
return ops.createIntList(IntStream.empty());
}
@Override
public <T> @Nullable T create(DynamicOps<T> ops, List<SnbtGrammar.IntegerLiteral> entries, ParseState<?> state) {
java.util.stream.IntStream.Builder result = IntStream.builder();
for (SnbtGrammar.IntegerLiteral entry : entries) {
Number parsedNumber = this.buildNumber(entry, state);
if (parsedNumber == null) {
return null;
}
result.add(parsedNumber.intValue());
}
return ops.createIntList(result.build());
}
},
LONG(SnbtGrammar.TypeSuffix.LONG, SnbtGrammar.TypeSuffix.BYTE, SnbtGrammar.TypeSuffix.SHORT, SnbtGrammar.TypeSuffix.INT) {
@Override
public <T> T create(DynamicOps<T> ops) {
return ops.createLongList(LongStream.empty());
}
@Override
public <T> @Nullable T create(DynamicOps<T> ops, List<SnbtGrammar.IntegerLiteral> entries, ParseState<?> state) {
java.util.stream.LongStream.Builder result = LongStream.builder();
for (SnbtGrammar.IntegerLiteral entry : entries) {
Number parsedNumber = this.buildNumber(entry, state);
if (parsedNumber == null) {
return null;
}
result.add(parsedNumber.longValue());
}
return ops.createLongList(result.build());
}
};
private final SnbtGrammar.TypeSuffix defaultType;
private final Set<SnbtGrammar.TypeSuffix> additionalTypes;
private ArrayPrefix(SnbtGrammar.TypeSuffix defaultType, SnbtGrammar.TypeSuffix... additionalTypes) {
this.additionalTypes = Set.of(additionalTypes);
this.defaultType = defaultType;
}
public boolean isAllowed(SnbtGrammar.TypeSuffix type) {
return type == this.defaultType || this.additionalTypes.contains(type);
}
public abstract <T> T create(DynamicOps<T> ops);
public abstract <T> @Nullable T create(DynamicOps<T> ops, List<SnbtGrammar.IntegerLiteral> entries, ParseState<?> state);
protected @Nullable Number buildNumber(SnbtGrammar.IntegerLiteral entry, ParseState<?> state) {
SnbtGrammar.TypeSuffix actualType = this.computeType(entry.suffix);
if (actualType == null) {
state.errorCollector().store(state.mark(), SnbtGrammar.ERROR_INVALID_ARRAY_ELEMENT_TYPE);
return null;
} else {
return (Number)entry.create(JavaOps.INSTANCE, actualType, state);
}
}
private SnbtGrammar.@Nullable TypeSuffix computeType(SnbtGrammar.IntegerSuffix value) {
SnbtGrammar.TypeSuffix type = value.type();
if (type == null) {
return this.defaultType;
} else {
return !this.isAllowed(type) ? null : type;
}
}
}
private static enum Base {
BINARY,
DECIMAL,
HEX;
}
private record IntegerLiteral(SnbtGrammar.Sign sign, SnbtGrammar.Base base, String digits, SnbtGrammar.IntegerSuffix suffix) {
private SnbtGrammar.SignedPrefix signedOrDefault() {
if (this.suffix.signed != null) {
return this.suffix.signed;
} else {
return switch (this.base) {
case BINARY, HEX -> SnbtGrammar.SignedPrefix.UNSIGNED;
case DECIMAL -> SnbtGrammar.SignedPrefix.SIGNED;
};
}
}
private String cleanupDigits(SnbtGrammar.Sign sign) {
boolean needsUnderscoreRemoval = SnbtGrammar.needsUnderscoreRemoval(this.digits);
if (sign != SnbtGrammar.Sign.MINUS && !needsUnderscoreRemoval) {
return this.digits;
} else {
StringBuilder result = new StringBuilder();
sign.append(result);
SnbtGrammar.cleanAndAppend(result, this.digits, needsUnderscoreRemoval);
return result.toString();
}
}
public <T> @Nullable T create(DynamicOps<T> ops, ParseState<?> state) {
return this.create(ops, Objects.requireNonNullElse(this.suffix.type, SnbtGrammar.TypeSuffix.INT), state);
}
public <T> @Nullable T create(DynamicOps<T> ops, SnbtGrammar.TypeSuffix type, ParseState<?> state) {
boolean isSigned = this.signedOrDefault() == SnbtGrammar.SignedPrefix.SIGNED;
if (!isSigned && this.sign == SnbtGrammar.Sign.MINUS) {
state.errorCollector().store(state.mark(), SnbtGrammar.ERROR_EXPECTED_NON_NEGATIVE_NUMBER);
return null;
} else {
String fixedDigits = this.cleanupDigits(this.sign);
int radix = switch (this.base) {
case BINARY -> 2;
case DECIMAL -> 10;
case HEX -> 16;
};
try {
if (isSigned) {
return (T)(switch (type) {
case BYTE -> ops.createByte(Byte.parseByte(fixedDigits, radix));
case SHORT -> ops.createShort(Short.parseShort(fixedDigits, radix));
case INT -> ops.createInt(Integer.parseInt(fixedDigits, radix));
case LONG -> ops.createLong(Long.parseLong(fixedDigits, radix));
default -> {
state.errorCollector().store(state.mark(), SnbtGrammar.ERROR_EXPECTED_INTEGER_TYPE);
yield null;
}
});
} else {
return (T)(switch (type) {
case BYTE -> ops.createByte(UnsignedBytes.parseUnsignedByte(fixedDigits, radix));
case SHORT -> ops.createShort(SnbtGrammar.parseUnsignedShort(fixedDigits, radix));
case INT -> ops.createInt(Integer.parseUnsignedInt(fixedDigits, radix));
case LONG -> ops.createLong(Long.parseUnsignedLong(fixedDigits, radix));
default -> {
state.errorCollector().store(state.mark(), SnbtGrammar.ERROR_EXPECTED_INTEGER_TYPE);
yield null;
}
});
}
} catch (NumberFormatException var8) {
state.errorCollector().store(state.mark(), SnbtGrammar.createNumberParseError(var8));
return null;
}
}
}
}
private record IntegerSuffix(SnbtGrammar.@Nullable SignedPrefix signed, SnbtGrammar.@Nullable TypeSuffix type) {
public static final SnbtGrammar.IntegerSuffix EMPTY = new SnbtGrammar.IntegerSuffix(null, null);
}
private static enum Sign {
PLUS,
MINUS;
public void append(StringBuilder output) {
if (this == MINUS) {
output.append("-");
}
}
}
private record Signed<T>(SnbtGrammar.Sign sign, T value) {
}
private static enum SignedPrefix {
SIGNED,
UNSIGNED;
}
private static class SimpleHexLiteralParseRule extends GreedyPredicateParseRule {
public SimpleHexLiteralParseRule(int size) {
super(size, size, DelayedException.create(SnbtGrammar.ERROR_EXPECTED_HEX_ESCAPE, String.valueOf(size)));
}
@Override
protected boolean isAccepted(char c) {
return switch (c) {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'a', 'b', 'c', 'd', 'e', 'f' -> true;
default -> false;
};
}
}
private static enum TypeSuffix {
FLOAT,
DOUBLE,
BYTE,
SHORT,
INT,
LONG;
}
}引用的其他类
-
- 引用位置:
方法调用/构造调用 - 关联成员:
BuiltinKey(), SnbtOperations.BuiltinKey()
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
Component.translatable(), Component.translatableEscape()
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
Atom.of()
- 引用位置:
-
- 引用位置:
字段/方法调用/返回值 - 关联成员:
DelayedException.create()
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
Term.alternative(), Term.cut(), Term.fail(), Term.marker(), Term.optional(), Term.positiveLookahead(), Term.repeated(), Term.repeatedWithTrailingSeparator(), Term.sequence()
- 引用位置:
-
- 引用位置:
返回值
- 引用位置:
-
- 引用位置:
构造调用 - 关联成员:
GreedyPatternParseRule()
- 引用位置:
-
- 引用位置:
字段/构造调用 - 关联成员:
GreedyPredicateParseRule()
- 引用位置:
-
- 引用位置:
字段/构造调用 - 关联成员:
NumberRunParseRule()
- 引用位置:
-
- 引用位置:
字段/方法调用/构造调用 - 关联成员:
StringReaderTerms.TerminalCharacters(), StringReaderTerms.character(), StringReaderTerms.characters(), TerminalCharacters()
- 引用位置:
-
- 引用位置:
构造调用 - 关联成员:
UnquotedStringParseRule()
- 引用位置:
-
- 引用位置:
字段/方法调用 - 关联成员:
Pattern.compile()
- 引用位置: