9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-19 15:09:15 +00:00

格式化

This commit is contained in:
jhqwqmc
2025-12-01 07:57:46 +08:00
parent 16aedafbe4
commit edfdf083e0
2 changed files with 334 additions and 224 deletions

View File

@@ -24,7 +24,7 @@ import java.util.stream.LongStream;
public class SnbtGrammar { public class SnbtGrammar {
private static final DynamicCommandExceptionType ERROR_NUMBER_PARSE_FAILURE = new LocalizedDynamicCommandExceptionType( private static final DynamicCommandExceptionType ERROR_NUMBER_PARSE_FAILURE = new LocalizedDynamicCommandExceptionType(
number -> new LocalizedMessage("warning.config.type.snbt.parser.number_parse_failure", String.valueOf(number)) message -> new LocalizedMessage("warning.config.type.snbt.parser.number_parse_failure", String.valueOf(message))
); );
static final DynamicCommandExceptionType ERROR_EXPECTED_HEX_ESCAPE = new LocalizedDynamicCommandExceptionType( static final DynamicCommandExceptionType ERROR_EXPECTED_HEX_ESCAPE = new LocalizedDynamicCommandExceptionType(
length -> new LocalizedMessage("warning.config.type.snbt.parser.expected_hex_escape", String.valueOf(length)) length -> new LocalizedMessage("warning.config.type.snbt.parser.expected_hex_escape", String.valueOf(length))
@@ -248,152 +248,151 @@ public class SnbtGrammar {
T emptyList = ops.emptyList(); T emptyList = ops.emptyList();
T nullString = ops.createString("null"); T nullString = ops.createString("null");
boolean isJavaType = "null".equals(nullString); // 确定是 Java 类型的 boolean isJavaType = "null".equals(nullString); // 确定是 Java 类型的
Dictionary<StringReader> rules = new Dictionary<>(); Dictionary<StringReader> rules = new Dictionary<>();
Atom<Sign> sign = Atom.of("sign"); Atom<Sign> sign = Atom.of("sign");
rules.put( rules.put(
sign, sign,
Term.alternative( Term.alternative(
Term.sequence(StringReaderTerms.character('+'), Term.marker(sign, Sign.PLUS)), Term.sequence(StringReaderTerms.character('+'), Term.marker(sign, Sign.PLUS)),
Term.sequence(StringReaderTerms.character('-'), Term.marker(sign, Sign.MINUS)) Term.sequence(StringReaderTerms.character('-'), Term.marker(sign, Sign.MINUS))
), ),
scope -> scope.getOrThrow(sign) scope -> scope.getOrThrow(sign)
); );
Atom<IntegerSuffix> integerSuffix = Atom.of("integer_suffix"); Atom<IntegerSuffix> integerSuffix = Atom.of("integer_suffix");
rules.put( rules.put(
integerSuffix, integerSuffix,
Term.alternative( Term.alternative(
Term.sequence(
StringReaderTerms.characters('u', 'U'),
Term.alternative(
Term.sequence( Term.sequence(
StringReaderTerms.characters('b', 'B'), StringReaderTerms.characters('u', 'U'),
Term.marker(integerSuffix, new IntegerSuffix(SignedPrefix.UNSIGNED, TypeSuffix.BYTE)) Term.alternative(
Term.sequence(StringReaderTerms.characters('b', 'B'), Term.marker(integerSuffix, new IntegerSuffix(SignedPrefix.UNSIGNED, TypeSuffix.BYTE))),
Term.sequence(StringReaderTerms.characters('s', 'S'), Term.marker(integerSuffix, new IntegerSuffix(SignedPrefix.UNSIGNED, TypeSuffix.SHORT))),
Term.sequence(StringReaderTerms.characters('i', 'I'), Term.marker(integerSuffix, new IntegerSuffix(SignedPrefix.UNSIGNED, TypeSuffix.INT))),
Term.sequence(StringReaderTerms.characters('l', 'L'), Term.marker(integerSuffix, new IntegerSuffix(SignedPrefix.UNSIGNED, TypeSuffix.LONG)))
)
), ),
Term.sequence( Term.sequence(
StringReaderTerms.characters('s', 'S'), StringReaderTerms.characters('s', 'S'),
Term.marker(integerSuffix, new IntegerSuffix(SignedPrefix.UNSIGNED, TypeSuffix.SHORT)) Term.alternative(
Term.sequence(StringReaderTerms.characters('b', 'B'), Term.marker(integerSuffix, new IntegerSuffix(SignedPrefix.SIGNED, TypeSuffix.BYTE))),
Term.sequence(StringReaderTerms.characters('s', 'S'), Term.marker(integerSuffix, new IntegerSuffix(SignedPrefix.SIGNED, TypeSuffix.SHORT))),
Term.sequence(StringReaderTerms.characters('i', 'I'), Term.marker(integerSuffix, new IntegerSuffix(SignedPrefix.SIGNED, TypeSuffix.INT))),
Term.sequence(StringReaderTerms.characters('l', 'L'), Term.marker(integerSuffix, new IntegerSuffix(SignedPrefix.SIGNED, TypeSuffix.LONG)))
)
), ),
Term.sequence( Term.sequence(StringReaderTerms.characters('b', 'B'), Term.marker(integerSuffix, new IntegerSuffix(null, TypeSuffix.BYTE))),
StringReaderTerms.characters('i', 'I'), Term.sequence(StringReaderTerms.characters('s', 'S'), Term.marker(integerSuffix, new IntegerSuffix(null, TypeSuffix.SHORT))),
Term.marker(integerSuffix, new IntegerSuffix(SignedPrefix.UNSIGNED, TypeSuffix.INT)) Term.sequence(StringReaderTerms.characters('i', 'I'), Term.marker(integerSuffix, new IntegerSuffix(null, TypeSuffix.INT))),
), Term.sequence(StringReaderTerms.characters('l', 'L'), Term.marker(integerSuffix, new IntegerSuffix(null, TypeSuffix.LONG)))
Term.sequence(
StringReaderTerms.characters('l', 'L'),
Term.marker(integerSuffix, new IntegerSuffix(SignedPrefix.UNSIGNED, TypeSuffix.LONG))
)
)
), ),
Term.sequence(
StringReaderTerms.characters('s', 'S'),
Term.alternative(
Term.sequence(
StringReaderTerms.characters('b', 'B'),
Term.marker(integerSuffix, new IntegerSuffix(SignedPrefix.SIGNED, TypeSuffix.BYTE))
),
Term.sequence(
StringReaderTerms.characters('s', 'S'),
Term.marker(integerSuffix, new IntegerSuffix(SignedPrefix.SIGNED, TypeSuffix.SHORT))
),
Term.sequence(
StringReaderTerms.characters('i', 'I'),
Term.marker(integerSuffix, new IntegerSuffix(SignedPrefix.SIGNED, TypeSuffix.INT))
),
Term.sequence(
StringReaderTerms.characters('l', 'L'),
Term.marker(integerSuffix, new IntegerSuffix(SignedPrefix.SIGNED, TypeSuffix.LONG))
)
)
),
Term.sequence(StringReaderTerms.characters('b', 'B'), Term.marker(integerSuffix, new IntegerSuffix(null, TypeSuffix.BYTE))),
Term.sequence(StringReaderTerms.characters('s', 'S'), Term.marker(integerSuffix, new IntegerSuffix(null, TypeSuffix.SHORT))),
Term.sequence(StringReaderTerms.characters('i', 'I'), Term.marker(integerSuffix, new IntegerSuffix(null, TypeSuffix.INT))),
Term.sequence(StringReaderTerms.characters('l', 'L'), Term.marker(integerSuffix, new IntegerSuffix(null, TypeSuffix.LONG)))
),
scope -> scope.getOrThrow(integerSuffix) scope -> scope.getOrThrow(integerSuffix)
); );
Atom<String> binaryNumeral = Atom.of("binary_numeral"); Atom<String> binaryNumeral = Atom.of("binary_numeral");
rules.put(binaryNumeral, BINARY_NUMERAL); rules.put(binaryNumeral, BINARY_NUMERAL);
Atom<String> decimalNumeral = Atom.of("decimal_numeral"); Atom<String> decimalNumeral = Atom.of("decimal_numeral");
rules.put(decimalNumeral, DECIMAL_NUMERAL); rules.put(decimalNumeral, DECIMAL_NUMERAL);
Atom<String> hexNumeral = Atom.of("hex_numeral"); Atom<String> hexNumeral = Atom.of("hex_numeral");
rules.put(hexNumeral, HEX_NUMERAL); rules.put(hexNumeral, HEX_NUMERAL);
Atom<IntegerLiteral> integerLiteral = Atom.of("integer_literal"); Atom<IntegerLiteral> integerLiteral = Atom.of("integer_literal");
NamedRule<StringReader, IntegerLiteral> integerLiteralRule = rules.put( NamedRule<StringReader, IntegerLiteral> integerLiteralRule = rules.put(
integerLiteral, integerLiteral,
Term.sequence( Term.sequence(
Term.optional(rules.named(sign)), Term.optional(rules.named(sign)),
Term.alternative(
Term.sequence(
StringReaderTerms.character('0'),
Term.cut(),
Term.alternative( Term.alternative(
Term.sequence(StringReaderTerms.characters('x', 'X'), Term.cut(), rules.named(hexNumeral)), Term.sequence(
Term.sequence(StringReaderTerms.characters('b', 'B'), rules.named(binaryNumeral)), StringReaderTerms.character('0'),
Term.sequence(rules.named(decimalNumeral), Term.cut(), Term.fail(ERROR_LEADING_ZERO_NOT_ALLOWED)), Term.cut(),
Term.marker(decimalNumeral, "0") Term.alternative(
) Term.sequence(StringReaderTerms.characters('x', 'X'), Term.cut(), rules.named(hexNumeral)),
), Term.sequence(StringReaderTerms.characters('b', 'B'), rules.named(binaryNumeral)),
rules.named(decimalNumeral) 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))
), ),
Term.optional(rules.named(integerSuffix)) scope -> {
), IntegerSuffix suffix = scope.getOrDefault(integerSuffix, IntegerSuffix.EMPTY);
scope -> { Sign signValue = scope.getOrDefault(sign, Sign.PLUS);
IntegerSuffix suffix = scope.getOrDefault(integerSuffix, IntegerSuffix.EMPTY); String decimalContents = scope.get(decimalNumeral);
Sign signValue = scope.getOrDefault(sign, Sign.PLUS); if (decimalContents != null) {
String decimalContents = scope.get(decimalNumeral); return new IntegerLiteral(signValue, Base.DECIMAL, decimalContents, suffix);
if (decimalContents != null) { }
return new IntegerLiteral(signValue, Base.DECIMAL, decimalContents, suffix); String hexContents = scope.get(hexNumeral);
if (hexContents != null) {
return new IntegerLiteral(signValue, Base.HEX, hexContents, suffix);
}
String binaryContents = scope.getOrThrow(binaryNumeral);
return new IntegerLiteral(signValue, Base.BINARY, binaryContents, suffix);
} }
String string1 = scope.get(hexNumeral);
if (string1 != null) {
return new IntegerLiteral(signValue, Base.HEX, string1, suffix);
}
String string2 = scope.getOrThrow(binaryNumeral);
return new IntegerLiteral(signValue, Base.BINARY, string2, suffix);
}
); );
Atom<TypeSuffix> floatTypeSuffix = Atom.of("float_type_suffix"); Atom<TypeSuffix> floatTypeSuffix = Atom.of("float_type_suffix");
rules.put( rules.put(
floatTypeSuffix, floatTypeSuffix,
Term.alternative( Term.alternative(
Term.sequence(StringReaderTerms.characters('f', 'F'), Term.marker(floatTypeSuffix, TypeSuffix.FLOAT)), Term.sequence(StringReaderTerms.characters('f', 'F'), Term.marker(floatTypeSuffix, TypeSuffix.FLOAT)),
Term.sequence(StringReaderTerms.characters('d', 'D'), Term.marker(floatTypeSuffix, TypeSuffix.DOUBLE)) Term.sequence(StringReaderTerms.characters('d', 'D'), Term.marker(floatTypeSuffix, TypeSuffix.DOUBLE))
), ),
scope -> scope.getOrThrow(floatTypeSuffix) scope -> scope.getOrThrow(floatTypeSuffix)
); );
Atom<Signed<String>> floatExponentPart = Atom.of("float_exponent_part"); Atom<Signed<String>> floatExponentPart = Atom.of("float_exponent_part");
rules.put( rules.put(
floatExponentPart, floatExponentPart,
Term.sequence(StringReaderTerms.characters('e', 'E'), Term.optional(rules.named(sign)), rules.named(decimalNumeral)), Term.sequence(
StringReaderTerms.characters('e', 'E'),
Term.optional(rules.named(sign)),
rules.named(decimalNumeral)
),
scope -> new Signed<>(scope.getOrDefault(sign, Sign.PLUS), scope.getOrThrow(decimalNumeral)) scope -> new Signed<>(scope.getOrDefault(sign, Sign.PLUS), scope.getOrThrow(decimalNumeral))
); );
Atom<String> floatWholePart = Atom.of("float_whole_part"); Atom<String> floatWholePart = Atom.of("float_whole_part");
Atom<String> floatFractionPart = Atom.of("float_fraction_part"); Atom<String> floatFractionPart = Atom.of("float_fraction_part");
Atom<T> floatLiteral = Atom.of("float_literal"); Atom<T> floatLiteral = Atom.of("float_literal");
rules.putComplex( rules.putComplex(
floatLiteral, floatLiteral,
Term.sequence( Term.sequence(
Term.optional(rules.named(sign)), Term.optional(rules.named(sign)),
Term.alternative( Term.alternative(
Term.sequence( Term.sequence(
rules.namedWithAlias(decimalNumeral, floatWholePart), rules.namedWithAlias(decimalNumeral, floatWholePart),
StringReaderTerms.character('.'), StringReaderTerms.character('.'),
Term.cut(), Term.cut(),
Term.optional(rules.namedWithAlias(decimalNumeral, floatFractionPart)), Term.optional(rules.namedWithAlias(decimalNumeral, floatFractionPart)),
Term.optional(rules.named(floatExponentPart)), Term.optional(rules.named(floatExponentPart)),
Term.optional(rules.named(floatTypeSuffix)) Term.optional(rules.named(floatTypeSuffix))
), ),
Term.sequence( Term.sequence(
StringReaderTerms.character('.'), StringReaderTerms.character('.'),
Term.cut(), Term.cut(),
rules.namedWithAlias(decimalNumeral, floatFractionPart), rules.namedWithAlias(decimalNumeral, floatFractionPart),
Term.optional(rules.named(floatExponentPart)), Term.optional(rules.named(floatExponentPart)),
Term.optional(rules.named(floatTypeSuffix)) Term.optional(rules.named(floatTypeSuffix))
), ),
Term.sequence(rules.namedWithAlias(decimalNumeral, floatWholePart), rules.named(floatExponentPart), Term.cut(), Term.optional(rules.named(floatTypeSuffix))), Term.sequence(
Term.sequence(rules.namedWithAlias(decimalNumeral, floatWholePart), Term.optional(rules.named(floatExponentPart)), rules.named(floatTypeSuffix)) 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 -> { state -> {
Scope scope = state.scope(); Scope scope = state.scope();
Sign wholeSign = scope.getOrDefault(sign, Sign.PLUS); Sign wholeSign = scope.getOrDefault(sign, Sign.PLUS);
@@ -402,116 +401,160 @@ public class SnbtGrammar {
Signed<String> exponent = scope.get(floatExponentPart); Signed<String> exponent = scope.get(floatExponentPart);
TypeSuffix typeSuffix = scope.get(floatTypeSuffix); TypeSuffix typeSuffix = scope.get(floatTypeSuffix);
return createFloat(ops, wholeSign, whole, fraction, exponent, typeSuffix, state); return createFloat(ops, wholeSign, whole, fraction, exponent, typeSuffix, state);
} }
); );
Atom<String> stringHex2 = Atom.of("string_hex_2"); Atom<String> stringHex2 = Atom.of("string_hex_2");
rules.put(stringHex2, new SimpleHexLiteralParseRule(2)); rules.put(stringHex2, new SimpleHexLiteralParseRule(2));
Atom<String> stringHex4 = Atom.of("string_hex_4"); Atom<String> stringHex4 = Atom.of("string_hex_4");
rules.put(stringHex4, new SimpleHexLiteralParseRule(4)); rules.put(stringHex4, new SimpleHexLiteralParseRule(4));
Atom<String> stringHex8 = Atom.of("string_hex_8"); Atom<String> stringHex8 = Atom.of("string_hex_8");
rules.put(stringHex8, new SimpleHexLiteralParseRule(8)); rules.put(stringHex8, new SimpleHexLiteralParseRule(8));
Atom<String> stringUnicodeName = Atom.of("string_unicode_name"); Atom<String> stringUnicodeName = Atom.of("string_unicode_name");
rules.put(stringUnicodeName, new GreedyPatternParseRule(UNICODE_NAME, ERROR_INVALID_CHARACTER_NAME)); rules.put(stringUnicodeName, new GreedyPatternParseRule(UNICODE_NAME, ERROR_INVALID_CHARACTER_NAME));
Atom<String> stringEscapeSequence = Atom.of("string_escape_sequence"); Atom<String> stringEscapeSequence = Atom.of("string_escape_sequence");
rules.putComplex( rules.putComplex(
stringEscapeSequence, stringEscapeSequence,
Term.alternative( Term.alternative(
Term.sequence(StringReaderTerms.character('b'), Term.marker(stringEscapeSequence, "\b")), Term.sequence(StringReaderTerms.character('b'), Term.marker(stringEscapeSequence, "\b")),
Term.sequence(StringReaderTerms.character('s'), Term.marker(stringEscapeSequence, " ")), Term.sequence(StringReaderTerms.character('s'), Term.marker(stringEscapeSequence, " ")),
Term.sequence(StringReaderTerms.character('t'), Term.marker(stringEscapeSequence, "\t")), Term.sequence(StringReaderTerms.character('t'), Term.marker(stringEscapeSequence, "\t")),
Term.sequence(StringReaderTerms.character('n'), Term.marker(stringEscapeSequence, "\n")), Term.sequence(StringReaderTerms.character('n'), Term.marker(stringEscapeSequence, "\n")),
Term.sequence(StringReaderTerms.character('f'), Term.marker(stringEscapeSequence, "\f")), Term.sequence(StringReaderTerms.character('f'), Term.marker(stringEscapeSequence, "\f")),
Term.sequence(StringReaderTerms.character('r'), Term.marker(stringEscapeSequence, "\r")), 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('\''), 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('x'), rules.named(stringHex2)),
Term.sequence(StringReaderTerms.character('u'), rules.named(stringHex4)), Term.sequence(StringReaderTerms.character('u'), rules.named(stringHex4)),
Term.sequence(StringReaderTerms.character('U'), rules.named(stringHex8)), Term.sequence(StringReaderTerms.character('U'), rules.named(stringHex8)),
Term.sequence(StringReaderTerms.character('N'), StringReaderTerms.character('{'), rules.named(stringUnicodeName), StringReaderTerms.character('}')) Term.sequence(
), StringReaderTerms.character('N'),
StringReaderTerms.character('{'),
rules.named(stringUnicodeName),
StringReaderTerms.character('}')
)
),
state -> { state -> {
Scope scope = state.scope(); Scope scope = state.scope();
String plainEscape = scope.getAny(stringEscapeSequence); String plainEscape = scope.getAny(stringEscapeSequence);
if (plainEscape != null) { if (plainEscape != null) {
return plainEscape; return plainEscape;
} }
String hexEscape = scope.getAny(stringHex2, stringHex4, stringHex8); String hexEscape = scope.getAny(stringHex2, stringHex4, stringHex8);
if (hexEscape != null) { if (hexEscape != null) {
int codePoint = HexFormat.fromHexDigits(hexEscape); int codePoint = HexFormat.fromHexDigits(hexEscape);
if (!Character.isValidCodePoint(codePoint)) { if (!Character.isValidCodePoint(codePoint)) {
state.errorCollector() state.errorCollector().store(state.mark(), DelayedException.create(ERROR_INVALID_CODEPOINT, String.format(Locale.ROOT, "U+%08X", codePoint)));
.store(state.mark(), DelayedException.create(ERROR_INVALID_CODEPOINT, String.format(Locale.ROOT, "U+%08X", codePoint))); return null;
return null; }
}
return Character.toString(codePoint); return Character.toString(codePoint);
} }
String character = scope.getOrThrow(stringUnicodeName); String character = scope.getOrThrow(stringUnicodeName);
int codePoint; int codePoint;
try { try {
codePoint = Character.codePointOf(character); codePoint = Character.codePointOf(character);
} catch (IllegalArgumentException var12x) { } catch (IllegalArgumentException var12x) {
state.errorCollector().store(state.mark(), ERROR_INVALID_CHARACTER_NAME); state.errorCollector().store(state.mark(), ERROR_INVALID_CHARACTER_NAME);
return null; return null;
} }
return Character.toString(codePoint); return Character.toString(codePoint);
} }
); );
Atom<String> stringPlainContents = Atom.of("string_plain_contents"); Atom<String> stringPlainContents = Atom.of("string_plain_contents");
rules.put(stringPlainContents, PLAIN_STRING_CHUNK); rules.put(stringPlainContents, PLAIN_STRING_CHUNK);
Atom<List<String>> stringChunks = Atom.of("string_chunks"); Atom<List<String>> stringChunks = Atom.of("string_chunks");
Atom<String> stringContents = Atom.of("string_contents"); Atom<String> stringContents = Atom.of("string_contents");
Atom<String> singleQuotedStringChunk = Atom.of("single_quoted_string_chunk"); Atom<String> singleQuotedStringChunk = Atom.of("single_quoted_string_chunk");
NamedRule<StringReader, String> namedRule1 = rules.put( NamedRule<StringReader, String> singleQuotedStringChunkRule = rules.put(
singleQuotedStringChunk, singleQuotedStringChunk,
Term.alternative( Term.alternative(
rules.namedWithAlias(stringPlainContents, stringContents), rules.namedWithAlias(stringPlainContents, stringContents),
Term.sequence(StringReaderTerms.character('\\'), rules.namedWithAlias(stringEscapeSequence, stringContents)), Term.sequence(StringReaderTerms.character('\\'), rules.namedWithAlias(stringEscapeSequence, stringContents)),
Term.sequence(StringReaderTerms.character('"'), Term.marker(stringContents, "\"")) Term.sequence(StringReaderTerms.character('"'), Term.marker(stringContents, "\""))
), ),
scope -> scope.getOrThrow(stringContents) scope -> scope.getOrThrow(stringContents)
); );
Atom<String> singleQuotedStringContents = Atom.of("single_quoted_string_contents"); Atom<String> singleQuotedStringContents = Atom.of("single_quoted_string_contents");
rules.put(singleQuotedStringContents, Term.repeated(namedRule1, stringChunks), scope -> joinList(scope.getOrThrow(stringChunks))); rules.put(
singleQuotedStringContents,
Term.repeated(singleQuotedStringChunkRule, stringChunks),
scope -> joinList(scope.getOrThrow(stringChunks))
);
Atom<String> doubleQuotedStringChunk = Atom.of("double_quoted_string_chunk"); Atom<String> doubleQuotedStringChunk = Atom.of("double_quoted_string_chunk");
NamedRule<StringReader, String> namedRule2 = rules.put( NamedRule<StringReader, String> doubleQuotedStringChunkRule = rules.put(
doubleQuotedStringChunk, doubleQuotedStringChunk,
Term.alternative( Term.alternative(
rules.namedWithAlias(stringPlainContents, stringContents), rules.namedWithAlias(stringPlainContents, stringContents),
Term.sequence(StringReaderTerms.character('\\'), rules.namedWithAlias(stringEscapeSequence, stringContents)), Term.sequence(StringReaderTerms.character('\\'), rules.namedWithAlias(stringEscapeSequence, stringContents)),
Term.sequence(StringReaderTerms.character('\''), Term.marker(stringContents, "'")) Term.sequence(StringReaderTerms.character('\''), Term.marker(stringContents, "'"))
), ),
scope -> scope.getOrThrow(stringContents) scope -> scope.getOrThrow(stringContents)
); );
Atom<String> doubleQuotedStringContents = Atom.of("double_quoted_string_contents"); Atom<String> doubleQuotedStringContents = Atom.of("double_quoted_string_contents");
rules.put(doubleQuotedStringContents, Term.repeated(namedRule2, stringChunks), scope -> joinList(scope.getOrThrow(stringChunks))); rules.put(
doubleQuotedStringContents,
Term.repeated(doubleQuotedStringChunkRule, stringChunks),
scope -> joinList(scope.getOrThrow(stringChunks))
);
Atom<String> quotedStringLiteral = Atom.of("quoted_string_literal"); Atom<String> quotedStringLiteral = Atom.of("quoted_string_literal");
rules.put( rules.put(
quotedStringLiteral, quotedStringLiteral,
Term.alternative( Term.alternative(
Term.sequence( Term.sequence(
StringReaderTerms.character('"'), Term.cut(), Term.optional(rules.namedWithAlias(doubleQuotedStringContents, stringContents)), StringReaderTerms.character('"') StringReaderTerms.character('"'),
Term.cut(),
Term.optional(rules.namedWithAlias(doubleQuotedStringContents, stringContents)),
StringReaderTerms.character('"')
),
Term.sequence(
StringReaderTerms.character('\''),
Term.optional(rules.namedWithAlias(singleQuotedStringContents, stringContents)),
StringReaderTerms.character('\'')
)
), ),
Term.sequence(StringReaderTerms.character('\''), Term.optional(rules.namedWithAlias(singleQuotedStringContents, stringContents)), StringReaderTerms.character('\''))
),
scope -> scope.getOrThrow(stringContents) scope -> scope.getOrThrow(stringContents)
); );
Atom<String> unquotedString = Atom.of("unquoted_string"); Atom<String> unquotedString = Atom.of("unquoted_string");
rules.put(unquotedString, new UnquotedStringParseRule(1, ERROR_EXPECTED_UNQUOTED_STRING)); rules.put(
unquotedString,
new UnquotedStringParseRule(1, ERROR_EXPECTED_UNQUOTED_STRING)
);
Atom<T> literal = Atom.of("literal"); Atom<T> literal = Atom.of("literal");
Atom<List<T>> argumentList = Atom.of("arguments"); Atom<List<T>> argumentList = Atom.of("arguments");
rules.put( rules.put(
argumentList, Term.repeatedWithTrailingSeparator(rules.forward(literal), argumentList, StringReaderTerms.character(TagParser.ELEMENT_SEPARATOR)), scope -> scope.getOrThrow(argumentList) argumentList,
Term.repeatedWithTrailingSeparator(
rules.forward(literal),
argumentList,
StringReaderTerms.character(TagParser.ELEMENT_SEPARATOR)
),
scope -> scope.getOrThrow(argumentList)
); );
Atom<T> unquotedStringOrBuiltIn = Atom.of("unquoted_string_or_builtin"); Atom<T> unquotedStringOrBuiltIn = Atom.of("unquoted_string_or_builtin");
rules.putComplex( rules.putComplex(
unquotedStringOrBuiltIn, unquotedStringOrBuiltIn,
Term.sequence( Term.sequence(
rules.named(unquotedString), rules.named(unquotedString),
Term.optional(Term.sequence(StringReaderTerms.character('('), rules.named(argumentList), StringReaderTerms.character(')'))) Term.optional(Term.sequence(
), StringReaderTerms.character('('),
rules.named(argumentList),
StringReaderTerms.character(')')
))
),
state -> { state -> {
Scope scope = state.scope(); Scope scope = state.scope();
String contents = scope.getOrThrow(unquotedString); String contents = scope.getOrThrow(unquotedString);
@@ -522,114 +565,192 @@ public class SnbtGrammar {
SnbtOperations.BuiltinOperation operation = SnbtOperations.BUILTIN_OPERATIONS.get(key); SnbtOperations.BuiltinOperation operation = SnbtOperations.BUILTIN_OPERATIONS.get(key);
if (operation != null) { if (operation != null) {
return operation.run(ops, arguments, state); return operation.run(ops, arguments, state);
} }
state.errorCollector().store(state.mark(), DelayedException.create(ERROR_NO_SUCH_OPERATION, key.toString())); state.errorCollector().store(state.mark(), DelayedException.create(ERROR_NO_SUCH_OPERATION, key.toString()));
return null; return null;
} else if (contents.equalsIgnoreCase("true")) { } else if (contents.equalsIgnoreCase("true")) {
return trueValue; return trueValue;
} else if (contents.equalsIgnoreCase("false")) { } else if (contents.equalsIgnoreCase("false")) {
return falseValue; return falseValue;
} else if (contents.equalsIgnoreCase("null")) { } else if (contents.equalsIgnoreCase("null")) {
return Objects.requireNonNullElseGet(ops.empty(), () -> { return Objects.requireNonNullElseGet(ops.empty(), () -> {
if (isJavaType) { if (isJavaType) {
return (T) CachedParseState.JAVA_NULL_VALUE_MARKER; return (T) CachedParseState.JAVA_NULL_VALUE_MARKER;
} }
return nullString; return nullString;
}); });
} }
return ops.createString(contents); return ops.createString(contents);
} }
state.errorCollector().store(state.mark(), SnbtOperations.BUILTIN_IDS, ERROR_INVALID_UNQUOTED_START); state.errorCollector().store(state.mark(), SnbtOperations.BUILTIN_IDS, ERROR_INVALID_UNQUOTED_START);
return null; return null;
} }
); );
Atom<String> mapKey = Atom.of("map_key"); Atom<String> mapKey = Atom.of("map_key");
rules.put(mapKey, Term.alternative(rules.named(quotedStringLiteral), rules.named(unquotedString)), scope -> scope.getAnyOrThrow(quotedStringLiteral, unquotedString)); 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"); Atom<Entry<String, T>> mapEntry = Atom.of("map_entry");
NamedRule<StringReader, Entry<String, T>> mapEntryRule = rules.putComplex( NamedRule<StringReader, Entry<String, T>> mapEntryRule = rules.putComplex(
mapEntry, Term.sequence(rules.named(mapKey), StringReaderTerms.character(TagParser.NAME_VALUE_SEPARATOR), rules.named(literal)), state -> { mapEntry,
Term.sequence(
rules.named(mapKey),
StringReaderTerms.character(TagParser.NAME_VALUE_SEPARATOR),
rules.named(literal)
),
state -> {
Scope scope = state.scope(); Scope scope = state.scope();
String key = scope.getOrThrow(mapKey); String key = scope.getOrThrow(mapKey);
if (key.isEmpty()) { if (key.isEmpty()) {
state.errorCollector().store(state.mark(), ERROR_EMPTY_KEY); state.errorCollector().store(state.mark(), ERROR_EMPTY_KEY);
return null; return null;
} }
T value = scope.getOrThrow(literal); T value = scope.getOrThrow(literal);
return Map.entry(key, value); return Map.entry(key, value);
} }
); );
Atom<List<Entry<String, T>>> mapEntries = Atom.of("map_entries"); Atom<List<Entry<String, T>>> mapEntries = Atom.of("map_entries");
rules.put(mapEntries, Term.repeatedWithTrailingSeparator(mapEntryRule, mapEntries, StringReaderTerms.character(TagParser.ELEMENT_SEPARATOR)), scope -> scope.getOrThrow(mapEntries)); rules.put(
mapEntries,
Term.repeatedWithTrailingSeparator(
mapEntryRule,
mapEntries,
StringReaderTerms.character(TagParser.ELEMENT_SEPARATOR)
),
scope -> scope.getOrThrow(mapEntries)
);
Atom<T> mapLiteral = Atom.of("map_literal"); Atom<T> mapLiteral = Atom.of("map_literal");
rules.put(mapLiteral, Term.sequence(StringReaderTerms.character('{'), Scope.increaseDepth(), rules.named(mapEntries), Scope.decreaseDepth(), StringReaderTerms.character('}')), scope -> { rules.put(
List<Entry<String, T>> entries = scope.getOrThrow(mapEntries); mapLiteral,
if (entries.isEmpty()) { Term.sequence(
return emptyMapValue; StringReaderTerms.character('{'),
} Scope.increaseDepth(),
Builder<T, T> builder = ImmutableMap.builderWithExpectedSize(entries.size()); rules.named(mapEntries),
Scope.decreaseDepth(),
StringReaderTerms.character('}')
),
scope -> {
List<Entry<String, T>> entries = scope.getOrThrow(mapEntries);
if (entries.isEmpty()) {
return emptyMapValue;
}
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());
}
);
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"); Atom<List<T>> listEntries = Atom.of("list_entries");
rules.put( rules.put(
listEntries, Term.repeatedWithTrailingSeparator(rules.forward(literal), listEntries, StringReaderTerms.character(TagParser.ELEMENT_SEPARATOR)), scope -> scope.getOrThrow(listEntries) listEntries,
Term.repeatedWithTrailingSeparator(
rules.forward(literal),
listEntries,
StringReaderTerms.character(TagParser.ELEMENT_SEPARATOR)
),
scope -> scope.getOrThrow(listEntries)
); );
Atom<ArrayPrefix> arrayPrefix = Atom.of("array_prefix"); Atom<ArrayPrefix> arrayPrefix = Atom.of("array_prefix");
rules.put( rules.put(
arrayPrefix, arrayPrefix,
Term.alternative( Term.alternative(
Term.sequence(StringReaderTerms.character('B'), Term.marker(arrayPrefix, ArrayPrefix.BYTE)), Term.sequence(StringReaderTerms.character('B'), Term.marker(arrayPrefix, ArrayPrefix.BYTE)),
Term.sequence(StringReaderTerms.character('L'), Term.marker(arrayPrefix, ArrayPrefix.LONG)), Term.sequence(StringReaderTerms.character('L'), Term.marker(arrayPrefix, ArrayPrefix.LONG)),
Term.sequence(StringReaderTerms.character('I'), Term.marker(arrayPrefix, ArrayPrefix.INT)) Term.sequence(StringReaderTerms.character('I'), Term.marker(arrayPrefix, ArrayPrefix.INT))
), ),
scope -> scope.getOrThrow(arrayPrefix) scope -> scope.getOrThrow(arrayPrefix)
); );
Atom<List<IntegerLiteral>> intArrayEntries = Atom.of("int_array_entries"); Atom<List<IntegerLiteral>> intArrayEntries = Atom.of("int_array_entries");
rules.put(intArrayEntries, Term.repeatedWithTrailingSeparator(integerLiteralRule, intArrayEntries, StringReaderTerms.character(TagParser.ELEMENT_SEPARATOR)), scope -> scope.getOrThrow(intArrayEntries)); rules.put(
intArrayEntries,
Term.repeatedWithTrailingSeparator(
integerLiteralRule,
intArrayEntries,
StringReaderTerms.character(TagParser.ELEMENT_SEPARATOR)
),
scope -> scope.getOrThrow(intArrayEntries)
);
Atom<T> listLiteral = Atom.of("list_literal"); Atom<T> listLiteral = Atom.of("list_literal");
rules.putComplex( rules.putComplex(
listLiteral, listLiteral,
Term.sequence( Term.sequence(
StringReaderTerms.character('['), StringReaderTerms.character('['),
Scope.increaseDepth(), Scope.increaseDepth(),
Term.alternative(Term.sequence(rules.named(arrayPrefix), StringReaderTerms.character(';'), rules.named(intArrayEntries)), rules.named(listEntries)), Term.alternative(
Scope.decreaseDepth(), Term.sequence(
StringReaderTerms.character(']') rules.named(arrayPrefix),
), StringReaderTerms.character(';'),
rules.named(intArrayEntries)
),
rules.named(listEntries)
),
Scope.decreaseDepth(),
StringReaderTerms.character(']')
),
state -> { state -> {
Scope scope = state.scope(); Scope scope = state.scope();
ArrayPrefix arrayType = scope.get(arrayPrefix); ArrayPrefix arrayType = scope.get(arrayPrefix);
if (arrayType != null) { if (arrayType != null) {
List<IntegerLiteral> entries = scope.getOrThrow(intArrayEntries); List<IntegerLiteral> entries = scope.getOrThrow(intArrayEntries);
return entries.isEmpty() ? arrayType.create(ops) : arrayType.create(ops, entries, state); return entries.isEmpty() ? arrayType.create(ops) : arrayType.create(ops, entries, state);
} }
List<T> entries = scope.getOrThrow(listEntries); List<T> entries = scope.getOrThrow(listEntries);
return entries.isEmpty() ? emptyList : ops.createList(entries.stream()); return entries.isEmpty() ? emptyList : ops.createList(entries.stream());
} }
); );
NamedRule<StringReader, T> literalRule = rules.putComplex( NamedRule<StringReader, T> literalRule = rules.putComplex(
literal, literal,
Term.alternative( Term.alternative(
Term.sequence(Term.positiveLookahead(NUMBER_LOOKEAHEAD), Term.alternative(rules.namedWithAlias(floatLiteral, literal), rules.named(integerLiteral))), Term.sequence(
Term.sequence(Term.positiveLookahead(StringReaderTerms.characters('"', '\'')), Term.cut(), rules.named(quotedStringLiteral)), Term.positiveLookahead(NUMBER_LOOKEAHEAD),
Term.sequence(Term.positiveLookahead(StringReaderTerms.character('{')), Term.cut(), rules.namedWithAlias(mapLiteral, literal)), Term.alternative(
Term.sequence(Term.positiveLookahead(StringReaderTerms.character('[')), Term.cut(), rules.namedWithAlias(listLiteral, literal)), rules.namedWithAlias(floatLiteral, literal),
rules.namedWithAlias(unquotedStringOrBuiltIn, 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 -> { state -> {
Scope scope = state.scope(); Scope scope = state.scope();
String quotedString = scope.get(quotedStringLiteral); String quotedString = scope.get(quotedStringLiteral);
if (quotedString != null) { if (quotedString != null) {
return ops.createString(quotedString); return ops.createString(quotedString);
} }
IntegerLiteral integer = scope.get(integerLiteral); IntegerLiteral integer = scope.get(integerLiteral);
return integer != null ? integer.create(ops, state) : scope.getOrThrow(literal); return integer != null ? integer.create(ops, state) : scope.getOrThrow(literal);
} }
); );
return new Grammar<>(rules, literalRule); return new Grammar<>(rules, literalRule);
} }
@@ -646,16 +767,13 @@ public class SnbtGrammar {
@Override @Override
public <T> T create(DynamicOps<T> ops, List<IntegerLiteral> entries, ParseState<?> state) { public <T> T create(DynamicOps<T> ops, List<IntegerLiteral> entries, ParseState<?> state) {
ByteList result = new ByteArrayList(); ByteList result = new ByteArrayList();
for (IntegerLiteral entry : entries) { for (IntegerLiteral entry : entries) {
Number number = this.buildNumber(entry, state); Number number = this.buildNumber(entry, state);
if (number == null) { if (number == null) {
return null; return null;
} }
result.add(number.byteValue()); result.add(number.byteValue());
} }
return ops.createByteList(ByteBuffer.wrap(result.toByteArray())); return ops.createByteList(ByteBuffer.wrap(result.toByteArray()));
} }
}, },
@@ -669,16 +787,13 @@ public class SnbtGrammar {
@Override @Override
public <T> T create(DynamicOps<T> ops, List<IntegerLiteral> entries, ParseState<?> state) { public <T> T create(DynamicOps<T> ops, List<IntegerLiteral> entries, ParseState<?> state) {
IntStream.Builder result = IntStream.builder(); IntStream.Builder result = IntStream.builder();
for (IntegerLiteral entry : entries) { for (IntegerLiteral entry : entries) {
Number parsedNumber = this.buildNumber(entry, state); Number parsedNumber = this.buildNumber(entry, state);
if (parsedNumber == null) { if (parsedNumber == null) {
return null; return null;
} }
result.add(parsedNumber.intValue()); result.add(parsedNumber.intValue());
} }
return ops.createIntList(result.build()); return ops.createIntList(result.build());
} }
}, },
@@ -692,16 +807,13 @@ public class SnbtGrammar {
@Override @Override
public <T> T create(DynamicOps<T> ops, List<IntegerLiteral> entries, ParseState<?> state) { public <T> T create(DynamicOps<T> ops, List<IntegerLiteral> entries, ParseState<?> state) {
LongStream.Builder result = LongStream.builder(); LongStream.Builder result = LongStream.builder();
for (IntegerLiteral entry : entries) { for (IntegerLiteral entry : entries) {
Number parsedNumber = this.buildNumber(entry, state); Number parsedNumber = this.buildNumber(entry, state);
if (parsedNumber == null) { if (parsedNumber == null) {
return null; return null;
} }
result.add(parsedNumber.longValue()); result.add(parsedNumber.longValue());
} }
return ops.createLongList(result.build()); return ops.createLongList(result.build());
} }
}; };
@@ -717,7 +829,6 @@ public class SnbtGrammar {
public boolean isAllowed(TypeSuffix type) { public boolean isAllowed(TypeSuffix type) {
return type == this.defaultType || this.additionalTypes.contains(type); return type == this.defaultType || this.additionalTypes.contains(type);
} }
public abstract <T> T create(DynamicOps<T> ops); public abstract <T> T create(DynamicOps<T> ops);
@Nullable @Nullable
@@ -742,7 +853,6 @@ public class SnbtGrammar {
return !this.isAllowed(type) ? null : type; return !this.isAllowed(type) ? null : type;
} }
} }
enum Base { enum Base {
BINARY, BINARY,
DECIMAL, DECIMAL,

View File

@@ -10,7 +10,7 @@ import java.util.Optional;
import java.util.function.Supplier; import java.util.function.Supplier;
public class LocalizedCommandSyntaxException extends CommandSyntaxException { public class LocalizedCommandSyntaxException extends CommandSyntaxException {
public static final int CONTEXT_AMOUNT = 10; public static final int CONTEXT_AMOUNT = 50;
public static final String PARSE_ERROR_NODE = "warning.config.type.snbt.invalid_syntax.parse_error"; public static final String PARSE_ERROR_NODE = "warning.config.type.snbt.invalid_syntax.parse_error";
public static final String HERE_NODE = "warning.config.type.snbt.invalid_syntax.here"; public static final String HERE_NODE = "warning.config.type.snbt.invalid_syntax.here";
private final Message message; private final Message message;