From 7a5bda03fbb024f6dc91fcef598a8a22a69c6559 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 5 Dec 2025 17:37:28 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=B9=E8=BF=9B=E8=AF=AD=E8=A8=80=E8=BE=93?= =?UTF-8?q?=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../item/modifier/ComponentsModifier.java | 4 +- .../config/template/ArgumentString.java | 4 +- .../core/util/snbt/SnbtGrammar.java | 1015 ----------------- .../core/util/snbt/SnbtOperations.java | 91 -- .../craftengine/core/util/snbt/TagParser.java | 97 -- .../core/util/snbt/parse/Atom.java | 15 - .../util/snbt/parse/CachedParseState.java | 235 ---- .../core/util/snbt/parse/Control.java | 18 - .../util/snbt/parse/DelayedException.java | 19 - .../core/util/snbt/parse/Dictionary.java | 93 -- .../core/util/snbt/parse/ErrorCollector.java | 97 -- .../core/util/snbt/parse/ErrorEntry.java | 4 - .../LocalizedCommandSyntaxException.java | 84 -- .../LocalizedDynamicCommandExceptionType.java | 27 - .../util/snbt/parse/LocalizedMessage.java | 53 - .../LocalizedSimpleCommandExceptionType.java | 25 - .../core/util/snbt/parse/NamedRule.java | 7 - .../core/util/snbt/parse/ParseState.java | 37 - .../core/util/snbt/parse/Rule.java | 51 - .../core/util/snbt/parse/Scope.java | 315 ----- .../util/snbt/parse/SuggestionSupplier.java | 11 - .../core/util/snbt/parse/Term.java | 235 ---- .../core/util/snbt/parse/grammar/Grammar.java | 51 - .../parse/grammar/GreedyPatternParseRule.java | 33 - .../grammar/GreedyPredicateParseRule.java | 48 - .../parse/grammar/NumberRunParseRule.java | 46 - .../grammar/StringReaderParserState.java | 29 - .../snbt/parse/grammar/StringReaderTerms.java | 64 -- .../grammar/UnquotedStringParseRule.java | 32 - gradle.properties | 2 +- 30 files changed, 5 insertions(+), 2837 deletions(-) delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/util/snbt/SnbtGrammar.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/util/snbt/SnbtOperations.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/util/snbt/TagParser.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/Atom.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/CachedParseState.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/Control.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/DelayedException.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/Dictionary.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/ErrorCollector.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/ErrorEntry.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/LocalizedCommandSyntaxException.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/LocalizedDynamicCommandExceptionType.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/LocalizedMessage.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/LocalizedSimpleCommandExceptionType.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/NamedRule.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/ParseState.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/Rule.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/Scope.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/SuggestionSupplier.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/Term.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/grammar/Grammar.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/grammar/GreedyPatternParseRule.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/grammar/GreedyPredicateParseRule.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/grammar/NumberRunParseRule.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/grammar/StringReaderParserState.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/grammar/StringReaderTerms.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/grammar/UnquotedStringParseRule.java diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ComponentsModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ComponentsModifier.java index e5f551690..d9a56564a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ComponentsModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ComponentsModifier.java @@ -9,7 +9,7 @@ import net.momirealms.craftengine.core.util.GsonHelper; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.Pair; import net.momirealms.craftengine.core.util.ResourceConfigUtils; -import net.momirealms.craftengine.core.util.snbt.TagParser; +import net.momirealms.craftengine.core.util.TagParser; import net.momirealms.sparrow.nbt.CompoundTag; import net.momirealms.sparrow.nbt.Tag; @@ -47,7 +47,7 @@ public class ComponentsModifier implements ItemDataModifier { String snbt = string.substring("(snbt) ".length()); try { return TagParser.parseTagFully(snbt); - } catch (CommandSyntaxException e) { + } catch (Exception e) { throw new LocalizedResourceConfigException("warning.config.type.snbt.invalid_syntax", e.getMessage()); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/ArgumentString.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/ArgumentString.java index 15f821b76..0241d73b2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/ArgumentString.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/ArgumentString.java @@ -3,7 +3,7 @@ package net.momirealms.craftengine.core.plugin.config.template; import com.mojang.brigadier.exceptions.CommandSyntaxException; import net.momirealms.craftengine.core.plugin.config.template.argument.TemplateArgument; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; -import net.momirealms.craftengine.core.util.snbt.TagParser; +import net.momirealms.craftengine.core.util.TagParser; import java.util.ArrayList; import java.util.List; @@ -71,7 +71,7 @@ public interface ArgumentString { Object parsed; try { parsed = TagParser.parseObjectFully(defaultValueString); - } catch (CommandSyntaxException e) { + } catch (Exception e) { throw new LocalizedResourceConfigException("warning.config.type.snbt.invalid_syntax", e.getMessage()); } try { diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/SnbtGrammar.java b/core/src/main/java/net/momirealms/craftengine/core/util/snbt/SnbtGrammar.java deleted file mode 100644 index 0ff4982f2..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/SnbtGrammar.java +++ /dev/null @@ -1,1015 +0,0 @@ -package net.momirealms.craftengine.core.util.snbt; - -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableMap.Builder; -import com.mojang.brigadier.StringReader; -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; -import com.mojang.serialization.DynamicOps; -import com.mojang.serialization.JavaOps; -import it.unimi.dsi.fastutil.bytes.ByteArrayList; -import it.unimi.dsi.fastutil.bytes.ByteList; -import it.unimi.dsi.fastutil.chars.CharList; -import net.momirealms.craftengine.core.util.VersionHelper; -import net.momirealms.craftengine.core.util.snbt.parse.*; -import net.momirealms.craftengine.core.util.snbt.parse.Dictionary; -import net.momirealms.craftengine.core.util.snbt.parse.grammar.*; -import net.momirealms.sparrow.nbt.codec.LegacyJavaOps; - -import javax.annotation.Nullable; -import java.nio.ByteBuffer; -import java.util.*; -import java.util.Map.Entry; -import java.util.regex.Pattern; -import java.util.stream.IntStream; -import java.util.stream.LongStream; - -public class SnbtGrammar { - private static final DynamicCommandExceptionType ERROR_NUMBER_PARSE_FAILURE = new LocalizedDynamicCommandExceptionType( - message -> new LocalizedMessage("warning.config.type.snbt.parser.number_parse_failure", String.valueOf(message)) - ); - static final DynamicCommandExceptionType ERROR_EXPECTED_HEX_ESCAPE = new LocalizedDynamicCommandExceptionType( - length -> new LocalizedMessage("warning.config.type.snbt.parser.expected_hex_escape", String.valueOf(length)) - ); - private static final DynamicCommandExceptionType ERROR_INVALID_CODEPOINT = new LocalizedDynamicCommandExceptionType( - codepoint -> new LocalizedMessage("warning.config.type.snbt.parser.invalid_codepoint", String.valueOf(codepoint)) - ); - private static final DynamicCommandExceptionType ERROR_NO_SUCH_OPERATION = new LocalizedDynamicCommandExceptionType( - operation -> new LocalizedMessage("warning.config.type.snbt.parser.no_such_operation", String.valueOf(operation)) - ); - static final DelayedException ERROR_EXPECTED_INTEGER_TYPE = DelayedException.create( - new LocalizedSimpleCommandExceptionType(new LocalizedMessage("warning.config.type.snbt.parser.expected_integer_type")) - ); - private static final DelayedException ERROR_EXPECTED_FLOAT_TYPE = DelayedException.create( - new LocalizedSimpleCommandExceptionType(new LocalizedMessage("warning.config.type.snbt.parser.expected_float_type")) - ); - static final DelayedException ERROR_EXPECTED_NON_NEGATIVE_NUMBER = DelayedException.create( - new LocalizedSimpleCommandExceptionType(new LocalizedMessage("warning.config.type.snbt.parser.expected_non_negative_number")) - ); - private static final DelayedException ERROR_INVALID_CHARACTER_NAME = DelayedException.create( - new LocalizedSimpleCommandExceptionType(new LocalizedMessage("warning.config.type.snbt.parser.invalid_character_name")) - ); - static final DelayedException ERROR_INVALID_ARRAY_ELEMENT_TYPE = DelayedException.create( - new LocalizedSimpleCommandExceptionType(new LocalizedMessage("warning.config.type.snbt.parser.invalid_array_element_type")) - ); - private static final DelayedException ERROR_INVALID_UNQUOTED_START = DelayedException.create( - new LocalizedSimpleCommandExceptionType(new LocalizedMessage("warning.config.type.snbt.parser.invalid_unquoted_start")) - ); - private static final DelayedException ERROR_EXPECTED_UNQUOTED_STRING = DelayedException.create( - new LocalizedSimpleCommandExceptionType(new LocalizedMessage("warning.config.type.snbt.parser.expected_unquoted_string")) - ); - private static final DelayedException ERROR_INVALID_STRING_CONTENTS = DelayedException.create( - new LocalizedSimpleCommandExceptionType(new LocalizedMessage("warning.config.type.snbt.parser.invalid_string_contents")) - ); - private static final DelayedException ERROR_EXPECTED_BINARY_NUMERAL = DelayedException.create( - new LocalizedSimpleCommandExceptionType(new LocalizedMessage("warning.config.type.snbt.parser.expected_binary_numeral")) - ); - private static final DelayedException ERROR_UNDERSCORE_NOT_ALLOWED = DelayedException.create( - new LocalizedSimpleCommandExceptionType(new LocalizedMessage("warning.config.type.snbt.parser.underscore_not_allowed")) - ); - private static final DelayedException ERROR_EXPECTED_DECIMAL_NUMERAL = DelayedException.create( - new LocalizedSimpleCommandExceptionType(new LocalizedMessage("warning.config.type.snbt.parser.expected_decimal_numeral")) - ); - private static final DelayedException ERROR_EXPECTED_HEX_NUMERAL = DelayedException.create( - new LocalizedSimpleCommandExceptionType(new LocalizedMessage("warning.config.type.snbt.parser.expected_hex_numeral")) - ); - private static final DelayedException ERROR_EMPTY_KEY = DelayedException.create( - new LocalizedSimpleCommandExceptionType(new LocalizedMessage("warning.config.type.snbt.parser.empty_key")) - ); - private static final DelayedException ERROR_LEADING_ZERO_NOT_ALLOWED = DelayedException.create( - new LocalizedSimpleCommandExceptionType(new LocalizedMessage("warning.config.type.snbt.parser.leading_zero_not_allowed")) - ); - private static final DelayedException ERROR_INFINITY_NOT_ALLOWED = DelayedException.create( - new LocalizedSimpleCommandExceptionType(new LocalizedMessage("warning.config.type.snbt.parser.infinity_not_allowed")) - ); - private static final NumberRunParseRule BINARY_NUMERAL = new NumberRunParseRule(ERROR_EXPECTED_BINARY_NUMERAL, ERROR_UNDERSCORE_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_UNDERSCORE_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_UNDERSCORE_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 canStartNumber(c); - } - }; - private static final Pattern UNICODE_NAME = Pattern.compile("[-a-zA-Z0-9 ]+"); - - static DelayedException createNumberParseError(NumberFormatException ex) { - return DelayedException.create(ERROR_NUMBER_PARSE_FAILURE, ex.getMessage()); - } - - private static boolean isAllowedToStartUnquotedString(char c) { - return !canStartNumber(c); - } - - static boolean canStartNumber(char c) { - return switch (c) { - case '+', '-', '.', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' -> true; - default -> false; - }; - } - - static boolean needsUnderscoreRemoval(String contents) { - return contents.indexOf(95) != -1; - } - - private static void cleanAndAppend(StringBuilder output, String contents) { - cleanAndAppend(output, contents, needsUnderscoreRemoval(contents)); - } - - static void cleanAndAppend(StringBuilder output, String contents, boolean needsUnderscoreRemoval) { - if (needsUnderscoreRemoval) { - for (char c : contents.toCharArray()) { - if (c != '_') { - output.append(c); - } - } - return; - } - output.append(contents); - } - - static short parseUnsignedShort(String string, int radix) { - int parse = Integer.parseInt(string, radix); - if (parse >> 16 == 0) { - return (short) parse; - } - throw new NumberFormatException("out of range: " + parse); - } - - @Nullable - private static T createFloat( - DynamicOps ops, - Sign sign, - @Nullable String whole, - @Nullable String fraction, - @Nullable Signed exponent, - @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 string = result.toString(); - - return switch (typeSuffix) { - case null -> convertDouble(ops, state, string); - case FLOAT -> convertFloat(ops, state, string); - case DOUBLE -> convertDouble(ops, state, string); - default -> { - state.errorCollector().store(state.mark(), ERROR_EXPECTED_FLOAT_TYPE); - yield null; - } - }; - } catch (NumberFormatException e) { - state.errorCollector().store(state.mark(), createNumberParseError(e)); - return null; - } - } - - @Nullable - private static T convertFloat(DynamicOps 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; - } - return ops.createFloat(value); - } - - @Nullable - private static T convertDouble(DynamicOps 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; - } - return ops.createDouble(value); - } - - private static String joinList(List list) { - return switch (list.size()) { - case 0 -> ""; - case 1 -> list.getFirst(); - default -> String.join("", list); - }; - } - - @SuppressWarnings("unchecked") - public static Grammar createParser(DynamicOps ops) { - T trueValue = ops.createBoolean(true); - T falseValue = ops.createBoolean(false); - T emptyMapValue = ops.emptyMap(); - T emptyList = ops.emptyList(); - T nullString = ops.createString(SnbtOperations.BUILTIN_NULL); - boolean isJavaType = SnbtOperations.BUILTIN_NULL.equals(nullString); // 确定是 Java 类型的 - - Dictionary rules = new Dictionary<>(); - - // 符号解析规则 - Atom sign = Atom.of("sign"); - rules.put( - sign, - Term.alternative( - Term.sequence(StringReaderTerms.character('+'), Term.marker(sign, Sign.PLUS)), - Term.sequence(StringReaderTerms.character('-'), Term.marker(sign, Sign.MINUS)) - ), - scope -> scope.getOrThrow(sign) - ); - - // 整数后缀解析规则 - Atom 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 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( - 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) - ); - - // 二进制解析规则 - Atom binaryNumeral = Atom.of("binary_numeral"); - rules.put(binaryNumeral, BINARY_NUMERAL); - - // 十进制解析规则 - Atom decimalNumeral = Atom.of("decimal_numeral"); - rules.put(decimalNumeral, DECIMAL_NUMERAL); - - // 十六进制解析规则 - Atom hexNumeral = Atom.of("hex_numeral"); - rules.put(hexNumeral, HEX_NUMERAL); - - // 整数常量解析规则 - Atom integerLiteral = Atom.of("integer_literal"); - NamedRule 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 -> { - IntegerSuffix suffix = scope.getOrDefault(integerSuffix, IntegerSuffix.EMPTY); - Sign signValue = scope.getOrDefault(sign, Sign.PLUS); - String decimalContents = scope.get(decimalNumeral); - 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); - } - ); - - // 浮点型后缀解析规则 - Atom floatTypeSuffix = Atom.of("float_type_suffix"); - rules.put( - floatTypeSuffix, - Term.alternative( - Term.sequence(StringReaderTerms.characters('f', 'F'), Term.marker(floatTypeSuffix, TypeSuffix.FLOAT)), - Term.sequence(StringReaderTerms.characters('d', 'D'), Term.marker(floatTypeSuffix, TypeSuffix.DOUBLE)) - ), - scope -> scope.getOrThrow(floatTypeSuffix) - ); - - // 浮点数指数部分解析规则 - Atom> 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 Signed<>(scope.getOrDefault(sign, Sign.PLUS), scope.getOrThrow(decimalNumeral)) - ); - - // 浮点数常量解析规则 - Atom floatWholePart = Atom.of("float_whole_part"); // 整数部分 - Atom floatFractionPart = Atom.of("float_fraction_part"); // 小数部分 - Atom 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(); - Sign wholeSign = scope.getOrDefault(sign, Sign.PLUS); - String whole = scope.get(floatWholePart); - String fraction = scope.get(floatFractionPart); - Signed exponent = scope.get(floatExponentPart); - TypeSuffix typeSuffix = scope.get(floatTypeSuffix); - return createFloat(ops, wholeSign, whole, fraction, exponent, typeSuffix, state); - } - ); - - // 二位十六进制字符串解析规则 - Atom stringHex2 = Atom.of("string_hex_2"); - rules.put(stringHex2, new SimpleHexLiteralParseRule(2)); - - // 四位十六进制字符串解析规则 - Atom stringHex4 = Atom.of("string_hex_4"); - rules.put(stringHex4, new SimpleHexLiteralParseRule(4)); - - // 八位十六进制字符串解析规则 - Atom stringHex8 = Atom.of("string_hex_8"); - rules.put(stringHex8, new SimpleHexLiteralParseRule(8)); - - // Unicode名称字符串解析规则 - Atom stringUnicodeName = Atom.of("string_unicode_name"); - rules.put(stringUnicodeName, new GreedyPatternParseRule(UNICODE_NAME, ERROR_INVALID_CHARACTER_NAME)); - - // 字符串转义序列解析规则 - Atom 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; - } - 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; - } - return Character.toString(codePoint); - } - 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 stringPlainContents = Atom.of("string_plain_contents"); - rules.put(stringPlainContents, PLAIN_STRING_CHUNK); - - // 字符串解析规则 - Atom> stringChunks = Atom.of("string_chunks"); // 字符串块 - Atom stringContents = Atom.of("string_contents"); // 字符串内容 - - // 单引号字符串块解析规则 - Atom singleQuotedStringChunk = Atom.of("single_quoted_string_chunk"); - NamedRule 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 singleQuotedStringContents = Atom.of("single_quoted_string_contents"); - rules.put( - singleQuotedStringContents, - Term.repeated(singleQuotedStringChunkRule, stringChunks), - scope -> joinList(scope.getOrThrow(stringChunks)) - ); - - // 双引号字符串块解析规则 - Atom doubleQuotedStringChunk = Atom.of("double_quoted_string_chunk"); - NamedRule 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 doubleQuotedStringContents = Atom.of("double_quoted_string_contents"); - rules.put( - doubleQuotedStringContents, - Term.repeated(doubleQuotedStringChunkRule, stringChunks), - scope -> joinList(scope.getOrThrow(stringChunks)) - ); - - // 带引号的字符串字面量解析规则 - Atom 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 unquotedString = Atom.of("unquoted_string"); - rules.put( - unquotedString, - new UnquotedStringParseRule(1, ERROR_EXPECTED_UNQUOTED_STRING) - ); - - // 列表解析规则 - Atom literal = Atom.of("literal"); // 字面量 - Atom> argumentList = Atom.of("arguments"); // 参数 - rules.put( - argumentList, - Term.repeatedWithTrailingSeparator( - rules.forward(literal), - argumentList, - StringReaderTerms.character(TagParser.ELEMENT_SEPARATOR) - ), - scope -> scope.getOrThrow(argumentList) - ); - - // 不带引号的字符串或内置表达式解析规则 - Atom 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 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); - } - state.errorCollector().store(state.mark(), DelayedException.create(ERROR_NO_SUCH_OPERATION, key.toString())); - return null; - } else if (contents.equalsIgnoreCase(SnbtOperations.BUILTIN_TRUE)) { // 解析不带引号的 true 为布尔值 - return trueValue; - } else if (contents.equalsIgnoreCase(SnbtOperations.BUILTIN_FALSE)) { // 解析不带引号的 false 为布尔值 - return falseValue; - } else if (contents.equalsIgnoreCase(SnbtOperations.BUILTIN_NULL)) { // 解析不带引号的 null 为空值,该功能并非标准 SNBT 语法 - return Objects.requireNonNullElseGet(ops.empty() /*一般来说这里都不会是null*/, () -> { - if (isJavaType) { - // 如果是 null 一般就是使用 Object 对象的 Java 类型,可以安全的强行转换 - return (T) CachedParseState.JAVA_NULL_VALUE_MARKER; - } - return nullString; // 意外情况保持 SNBT 默认行为 - }); - } - return ops.createString(contents); - } - state.errorCollector().store(state.mark(), SnbtOperations.BUILTIN_IDS, ERROR_INVALID_UNQUOTED_START); - return null; - } - ); - - // 映射键解析规则 - Atom mapKey = Atom.of("map_key"); - rules.put( - mapKey, - Term.alternative( - rules.named(quotedStringLiteral), - rules.named(unquotedString) - ), - scope -> scope.getAnyOrThrow(quotedStringLiteral, unquotedString) - ); - - // 映射条目解析规则 - Atom> mapEntry = Atom.of("map_entry"); - NamedRule> mapEntryRule = rules.putComplex( - mapEntry, - Term.sequence( - rules.named(mapKey), - StringReaderTerms.character(TagParser.NAME_VALUE_SEPARATOR), - 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; - } - T value = scope.getOrThrow(literal); - return Map.entry(key, value); - } - ); - - // 映射条目集合解析规则 - Atom>> mapEntries = Atom.of("map_entries"); - rules.put( - mapEntries, - Term.repeatedWithTrailingSeparator( - mapEntryRule, - mapEntries, - StringReaderTerms.character(TagParser.ELEMENT_SEPARATOR) - ), - scope -> scope.getOrThrow(mapEntries) - ); - - // 映射字面量解析规则 - Atom mapLiteral = Atom.of("map_literal"); - rules.put( - mapLiteral, - Term.sequence( - StringReaderTerms.character('{'), - Scope.increaseDepth(), - rules.named(mapEntries), - Scope.decreaseDepth(), - StringReaderTerms.character('}') - ), - scope -> { - List> entries = scope.getOrThrow(mapEntries); - if (entries.isEmpty()) { - return emptyMapValue; - } - Builder builder = ImmutableMap.builderWithExpectedSize(entries.size()); - for (Entry e : entries) { - builder.put(ops.createString(e.getKey()), e.getValue()); - } - return ops.createMap(builder.buildKeepingLast()); - } - ); - - // 列表条目集合解析规则 - Atom> listEntries = Atom.of("list_entries"); - rules.put( - listEntries, - Term.repeatedWithTrailingSeparator( - rules.forward(literal), - listEntries, - StringReaderTerms.character(TagParser.ELEMENT_SEPARATOR) - ), - scope -> scope.getOrThrow(listEntries) - ); - - // 数组前缀解析规则 - Atom arrayPrefix = Atom.of("array_prefix"); - rules.put( - arrayPrefix, - Term.alternative( - Term.sequence(StringReaderTerms.character('B'), Term.marker(arrayPrefix, ArrayPrefix.BYTE)), - Term.sequence(StringReaderTerms.character('L'), Term.marker(arrayPrefix, ArrayPrefix.LONG)), - Term.sequence(StringReaderTerms.character('I'), Term.marker(arrayPrefix, ArrayPrefix.INT)) - ), - scope -> scope.getOrThrow(arrayPrefix) - ); - - // 整数数组条目集合解析规则 - Atom> intArrayEntries = Atom.of("int_array_entries"); - rules.put( - intArrayEntries, - Term.repeatedWithTrailingSeparator( - integerLiteralRule, - intArrayEntries, - StringReaderTerms.character(TagParser.ELEMENT_SEPARATOR) - ), - scope -> scope.getOrThrow(intArrayEntries) - ); - - // 列表字面量解析规则 - Atom listLiteral = Atom.of("list_literal"); - rules.putComplex( - listLiteral, - Term.sequence( - StringReaderTerms.character('['), - Scope.increaseDepth(), - Term.alternative( - Term.sequence( - rules.named(arrayPrefix), - StringReaderTerms.character(';'), - rules.named(intArrayEntries) - ), - rules.named(listEntries) - ), - Scope.decreaseDepth(), - StringReaderTerms.character(']') - ), - state -> { - Scope scope = state.scope(); - ArrayPrefix arrayType = scope.get(arrayPrefix); - if (arrayType != null) { - List entries = scope.getOrThrow(intArrayEntries); - return entries.isEmpty() ? arrayType.create(ops) : arrayType.create(ops, entries, state); - } - List entries = scope.getOrThrow(listEntries); - return entries.isEmpty() ? emptyList : ops.createList(entries.stream()); - } - ); - - // 基本规则解析规则 - NamedRule 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); - } - IntegerLiteral integer = scope.get(integerLiteral); - return integer != null ? integer.create(ops, state) : scope.getOrThrow(literal); - } - ); - - return new Grammar<>(rules, literalRule); - } - - enum ArrayPrefix { - BYTE(TypeSuffix.BYTE) { - private static final ByteBuffer EMPTY_BUFFER = ByteBuffer.wrap(new byte[0]); - - @Override - public T create(DynamicOps ops) { - return ops.createByteList(EMPTY_BUFFER); - } - - @Nullable - @Override - public T create(DynamicOps ops, List entries, ParseState state) { - ByteList result = new ByteArrayList(); - for (IntegerLiteral entry : entries) { - Number number = this.buildNumber(entry, state); - if (number == null) { - return null; - } - result.add(number.byteValue()); - } - return ops.createByteList(ByteBuffer.wrap(result.toByteArray())); - } - }, - INT(TypeSuffix.INT, TypeSuffix.BYTE, TypeSuffix.SHORT) { - @Override - public T create(DynamicOps ops) { - return ops.createIntList(IntStream.empty()); - } - - @Nullable - @Override - public T create(DynamicOps ops, List entries, ParseState state) { - IntStream.Builder result = IntStream.builder(); - for (IntegerLiteral entry : entries) { - Number parsedNumber = this.buildNumber(entry, state); - if (parsedNumber == null) { - return null; - } - result.add(parsedNumber.intValue()); - } - return ops.createIntList(result.build()); - } - }, - LONG(TypeSuffix.LONG, TypeSuffix.BYTE, TypeSuffix.SHORT, TypeSuffix.INT) { - @Override - public T create(DynamicOps ops) { - return ops.createLongList(LongStream.empty()); - } - - @Nullable - @Override - public T create(DynamicOps ops, List entries, ParseState state) { - LongStream.Builder result = LongStream.builder(); - for (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 TypeSuffix defaultType; - private final Set additionalTypes; - - ArrayPrefix(final TypeSuffix defaultType, final TypeSuffix... additionalTypes) { - this.additionalTypes = Set.of(additionalTypes); - this.defaultType = defaultType; - } - - public boolean isAllowed(TypeSuffix type) { - return type == this.defaultType || this.additionalTypes.contains(type); - } - public abstract T create(DynamicOps ops); - - @Nullable - public abstract T create(DynamicOps ops, List entries, ParseState state); - - @Nullable - protected Number buildNumber(IntegerLiteral entry, ParseState state) { - TypeSuffix actualType = this.computeType(entry.suffix); - if (actualType == null) { - state.errorCollector().store(state.mark(), ERROR_INVALID_ARRAY_ELEMENT_TYPE); - return null; - } - return (Number) entry.create(VersionHelper.isOrAbove1_20_5() ? JavaOps.INSTANCE : LegacyJavaOps.INSTANCE, actualType, state); - } - - @Nullable - private TypeSuffix computeType(IntegerSuffix value) { - TypeSuffix type = value.type(); - if (type == null) { - return this.defaultType; - } - return !this.isAllowed(type) ? null : type; - } - } - enum Base { - BINARY, - DECIMAL, - HEX - } - - record IntegerLiteral(Sign sign, Base base, String digits, IntegerSuffix suffix) { - private SignedPrefix signedOrDefault() { - return Objects.requireNonNullElseGet(this.suffix.signed, () -> switch (this.base) { - case BINARY, HEX -> SignedPrefix.UNSIGNED; - case DECIMAL -> SignedPrefix.SIGNED; - }); - } - - private String cleanupDigits(Sign sign) { - boolean needsUnderscoreRemoval = needsUnderscoreRemoval(this.digits); - if (sign != Sign.MINUS && !needsUnderscoreRemoval) { - return this.digits; - } - StringBuilder result = new StringBuilder(); - sign.append(result); - cleanAndAppend(result, this.digits, needsUnderscoreRemoval); - return result.toString(); - } - - @Nullable - public T create(DynamicOps ops, ParseState state) { - return this.create(ops, Objects.requireNonNullElse(this.suffix.type, TypeSuffix.INT), state); - } - - @Nullable - public T create(DynamicOps ops, TypeSuffix type, ParseState state) { - boolean isSigned = this.signedOrDefault() == SignedPrefix.SIGNED; - if (!isSigned && this.sign == Sign.MINUS) { - state.errorCollector().store(state.mark(), ERROR_EXPECTED_NON_NEGATIVE_NUMBER); - return null; - } - String fixedDigits = this.cleanupDigits(this.sign); - - int radix = switch (this.base) { - case BINARY -> 2; - case DECIMAL -> 10; - case HEX -> 16; - }; - - try { - if (isSigned) { - return 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(), ERROR_EXPECTED_INTEGER_TYPE); - yield null; - } - }; - } - return switch (type) { - case BYTE -> ops.createByte(com.google.common.primitives.UnsignedBytes.parseUnsignedByte(fixedDigits, radix)); - case SHORT -> ops.createShort(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(), ERROR_EXPECTED_INTEGER_TYPE); - yield null; - } - }; - } catch (NumberFormatException var8) { - state.errorCollector().store(state.mark(), createNumberParseError(var8)); - return null; - } - } - } - - record IntegerSuffix(@Nullable SignedPrefix signed, @Nullable TypeSuffix type) { - public static final IntegerSuffix EMPTY = new IntegerSuffix(null, null); - } - - enum Sign { - PLUS, - MINUS; - - public void append(StringBuilder output) { - if (this == MINUS) { - output.append("-"); - } - } - } - - record Signed(Sign sign, T value) { - } - - enum SignedPrefix { - SIGNED, - UNSIGNED - } - - static class SimpleHexLiteralParseRule extends GreedyPredicateParseRule { - public SimpleHexLiteralParseRule(int size) { - super(size, size, DelayedException.create(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; - }; - } - } - - enum TypeSuffix { - FLOAT, - DOUBLE, - BYTE, - SHORT, - INT, - LONG - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/SnbtOperations.java b/core/src/main/java/net/momirealms/craftengine/core/util/snbt/SnbtOperations.java deleted file mode 100644 index c715eba12..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/SnbtOperations.java +++ /dev/null @@ -1,91 +0,0 @@ -package net.momirealms.craftengine.core.util.snbt; - -import com.mojang.brigadier.StringReader; -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import com.mojang.serialization.DynamicOps; -import net.momirealms.craftengine.core.util.snbt.parse.*; -import net.momirealms.sparrow.nbt.util.UUIDUtil; -import org.jetbrains.annotations.NotNull; - -import javax.annotation.Nullable; -import java.util.*; -import java.util.stream.Collectors; -import java.util.stream.IntStream; -import java.util.stream.Stream; - -public class SnbtOperations { - static final DelayedException ERROR_EXPECTED_STRING_UUID = DelayedException.create( - new LocalizedSimpleCommandExceptionType(new LocalizedMessage("warning.config.type.snbt.parser.expected_string_uuid")) - ); - static final DelayedException ERROR_EXPECTED_NUMBER_OR_BOOLEAN = DelayedException.create( - new LocalizedSimpleCommandExceptionType(new LocalizedMessage("warning.config.type.snbt.parser.expected_number_or_boolean")) - ); - public static final String BUILTIN_TRUE = "true"; - public static final String BUILTIN_FALSE = "false"; - public static final String BUILTIN_NULL = "null"; - public static final Map BUILTIN_OPERATIONS = Map.of( - new BuiltinKey("bool", 1), new BuiltinOperation() { - @Override - public T run(DynamicOps ops, List arguments, ParseState state) { - Boolean result = convert(ops, arguments.getFirst()); - if (result == null) { - state.errorCollector().store(state.mark(), SnbtOperations.ERROR_EXPECTED_NUMBER_OR_BOOLEAN); - return null; - } - return ops.createBoolean(result); - } - - @Nullable - private static Boolean convert(DynamicOps ops, T arg) { - Optional asBoolean = ops.getBooleanValue(arg).result(); - if (asBoolean.isPresent()) { - return asBoolean.get(); - } else { - Optional asNumber = ops.getNumberValue(arg).result(); - return asNumber.isPresent() ? asNumber.get().doubleValue() != 0.0 : null; - } - } - }, new BuiltinKey("uuid", 1), new BuiltinOperation() { - @Override - public T run(DynamicOps ops, List arguments, ParseState state) { - Optional arg = ops.getStringValue(arguments.getFirst()).result(); - if (arg.isEmpty()) { - state.errorCollector().store(state.mark(), SnbtOperations.ERROR_EXPECTED_STRING_UUID); - return null; - } - UUID uuid; - try { - uuid = UUID.fromString(arg.get()); - } catch (IllegalArgumentException var7) { - state.errorCollector().store(state.mark(), SnbtOperations.ERROR_EXPECTED_STRING_UUID); - return null; - } - - return ops.createIntList(IntStream.of(UUIDUtil.uuidToIntArray(uuid))); - } - } - ); - public static final SuggestionSupplier BUILTIN_IDS = new SuggestionSupplier<>() { - private final Set keys = Stream.concat( - Stream.of(BUILTIN_FALSE, BUILTIN_TRUE, BUILTIN_NULL), SnbtOperations.BUILTIN_OPERATIONS.keySet().stream().map(BuiltinKey::id) - ) - .collect(Collectors.toSet()); - - @Override - public Stream possibleValues(ParseState state) { - return this.keys.stream(); - } - }; - - public record BuiltinKey(String id, int argCount) { - @Override - public @NotNull String toString() { - return this.id + "/" + this.argCount; - } - } - - public interface BuiltinOperation { - @Nullable - T run(DynamicOps ops, List arguments, ParseState state); - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/TagParser.java b/core/src/main/java/net/momirealms/craftengine/core/util/snbt/TagParser.java deleted file mode 100644 index f963c635a..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/TagParser.java +++ /dev/null @@ -1,97 +0,0 @@ -package net.momirealms.craftengine.core.util.snbt; - -import com.mojang.brigadier.StringReader; -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; -import com.mojang.serialization.DynamicOps; -import com.mojang.serialization.JavaOps; -import net.momirealms.craftengine.core.util.VersionHelper; -import net.momirealms.craftengine.core.util.snbt.parse.LocalizedMessage; -import net.momirealms.craftengine.core.util.snbt.parse.LocalizedSimpleCommandExceptionType; -import net.momirealms.craftengine.core.util.snbt.parse.grammar.Grammar; -import net.momirealms.sparrow.nbt.CompoundTag; -import net.momirealms.sparrow.nbt.Tag; -import net.momirealms.sparrow.nbt.codec.LegacyJavaOps; -import net.momirealms.sparrow.nbt.codec.LegacyNBTOps; -import net.momirealms.sparrow.nbt.codec.NBTOps; - -@SuppressWarnings("unused") -public class TagParser { - public static final SimpleCommandExceptionType ERROR_TRAILING_DATA = new LocalizedSimpleCommandExceptionType( - new LocalizedMessage("warning.config.type.snbt.parser.trailing") - ); - public static final SimpleCommandExceptionType ERROR_EXPECTED_COMPOUND = new LocalizedSimpleCommandExceptionType( - new LocalizedMessage("warning.config.type.snbt.parser.expected.compound") - ); - public static final char ELEMENT_SEPARATOR = ','; - public static final char NAME_VALUE_SEPARATOR = ':'; - public static final TagParser NBT_OPS_PARSER = create(VersionHelper.isOrAbove1_20_5() ? NBTOps.INSTANCE : LegacyNBTOps.INSTANCE); - public static final TagParser JAVA_OPS_PARSER = create(VersionHelper.isOrAbove1_20_5() ? JavaOps.INSTANCE : LegacyJavaOps.INSTANCE); - private final DynamicOps ops; - private final Grammar grammar; - - private TagParser(DynamicOps ops, Grammar grammar) { - this.ops = ops; - this.grammar = grammar; - } - - public DynamicOps ops() { - return this.ops; - } - - public static TagParser create(DynamicOps ops) { - return new TagParser<>(ops, SnbtGrammar.createParser(ops)); - } - - private static CompoundTag castToCompoundOrThrow(StringReader reader, Tag result) throws CommandSyntaxException { - if (result instanceof CompoundTag compoundTag) { - return compoundTag; - } - throw ERROR_EXPECTED_COMPOUND.createWithContext(reader); - } - public static CompoundTag parseCompoundFully(String input) throws CommandSyntaxException { - StringReader reader = new StringReader(input); - Tag result = NBT_OPS_PARSER.parseFully(reader); - return castToCompoundOrThrow(reader, result); - } - - public static Tag parseTagFully(String input) throws CommandSyntaxException { - StringReader reader = new StringReader(input); - return NBT_OPS_PARSER.parseFully(reader); - } - - public static Object parseObjectFully(String input) throws CommandSyntaxException { - StringReader reader = new StringReader(input); - return JAVA_OPS_PARSER.parseFully(reader); - } - - public T parseFully(String input) throws CommandSyntaxException { - return this.parseFully(new StringReader(input)); - } - - public T parseFully(StringReader reader) throws CommandSyntaxException { - T result = this.grammar.parse(reader); - reader.skipWhitespace(); - if (reader.canRead()) { - throw ERROR_TRAILING_DATA.createWithContext(reader); - } - return result; - } - - public T parseAsArgument(StringReader reader) throws CommandSyntaxException { - return this.grammar.parse(reader); - } - - public static CompoundTag parseCompoundAsArgument(StringReader reader) throws CommandSyntaxException { - Tag result = parseTagAsArgument(reader); - return castToCompoundOrThrow(reader, result); - } - - public static Tag parseTagAsArgument(StringReader reader) throws CommandSyntaxException { - return NBT_OPS_PARSER.parseAsArgument(reader); - } - - public static Object parseObjectAsArgument(StringReader reader) throws CommandSyntaxException { - return JAVA_OPS_PARSER.parseAsArgument(reader); - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/Atom.java b/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/Atom.java deleted file mode 100644 index 1601e947b..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/Atom.java +++ /dev/null @@ -1,15 +0,0 @@ -package net.momirealms.craftengine.core.util.snbt.parse; - -import org.jetbrains.annotations.NotNull; - -@SuppressWarnings("unused") -public record Atom(String name) { - @Override - public @NotNull String toString() { - return "<" + this.name + ">"; - } - - public static Atom of(String name) { - return new Atom<>(name); - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/CachedParseState.java b/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/CachedParseState.java deleted file mode 100644 index b71d66c24..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/CachedParseState.java +++ /dev/null @@ -1,235 +0,0 @@ -package net.momirealms.craftengine.core.util.snbt.parse; - -import net.momirealms.craftengine.core.util.MiscUtils; - -import javax.annotation.Nullable; - -@SuppressWarnings("unchecked") -public abstract class CachedParseState implements ParseState { - private PositionCache[] positionCache = new PositionCache[256]; - private final ErrorCollector errorCollector; - private final Scope scope = new Scope(); - private SimpleControl[] controlCache = new SimpleControl[16]; - private int nextControlToReturn; - private final Silent silent = new Silent(); - public static final Object JAVA_NULL_VALUE_MARKER = new Object() { - @Override - public String toString() { - return "null"; - } - }; - - protected CachedParseState(ErrorCollector errorCollector) { - this.errorCollector = errorCollector; - } - - @Override - public Scope scope() { - return this.scope; - } - - @Override - public ErrorCollector errorCollector() { - return this.errorCollector; - } - - @Nullable - @Override - public T parse(NamedRule rule) { - int markBeforeParse = this.mark(); - PositionCache positionCache = this.getCacheForPosition(markBeforeParse); - int entryIndex = positionCache.findKeyIndex(rule.name()); - if (entryIndex != -1) { - CacheEntry value = positionCache.getValue(entryIndex); - if (value != null) { - if (value == CachedParseState.CacheEntry.NEGATIVE) { - return null; - } - this.restore(value.markAfterParse); - return value.value; - } - } else { - entryIndex = positionCache.allocateNewEntry(rule.name()); - } - - T result = rule.value().parse(this); - CacheEntry entry; - if (result == null) { - entry = CacheEntry.negativeEntry(); - } else { - int markAfterParse = this.mark(); - entry = new CacheEntry<>(result, markAfterParse); - } - - positionCache.setValue(entryIndex, entry); - return result; - } - - private PositionCache getCacheForPosition(int index) { - int currentSize = this.positionCache.length; - if (index >= currentSize) { - int newSize = MiscUtils.growByHalf(currentSize, index + 1); - PositionCache[] newCache = new PositionCache[newSize]; - System.arraycopy(this.positionCache, 0, newCache, 0, currentSize); - this.positionCache = newCache; - } - - PositionCache result = this.positionCache[index]; - if (result == null) { - result = new PositionCache(); - this.positionCache[index] = result; - } - - return result; - } - - @Override - public Control acquireControl() { - int currentSize = this.controlCache.length; - if (this.nextControlToReturn >= currentSize) { - int newSize = MiscUtils.growByHalf(currentSize, this.nextControlToReturn + 1); - SimpleControl[] newControlCache = new SimpleControl[newSize]; - System.arraycopy(this.controlCache, 0, newControlCache, 0, currentSize); - this.controlCache = newControlCache; - } - - int controlIndex = this.nextControlToReturn++; - SimpleControl entry = this.controlCache[controlIndex]; - if (entry == null) { - entry = new SimpleControl(); - this.controlCache[controlIndex] = entry; - } else { - entry.reset(); - } - - return entry; - } - - @Override - public void releaseControl() { - this.nextControlToReturn--; - } - - @Override - public ParseState silent() { - return this.silent; - } - - record CacheEntry(@Nullable T value, int markAfterParse) { - public static final CacheEntry NEGATIVE = new CacheEntry<>(null, -1); - - public static CacheEntry negativeEntry() { - return (CacheEntry) NEGATIVE; - } - } - - static class PositionCache { - public static final int ENTRY_STRIDE = 2; - private static final int NOT_FOUND = -1; - private Object[] atomCache = new Object[16]; - private int nextKey; - - public int findKeyIndex(Atom key) { - for (int i = 0; i < this.nextKey; i += ENTRY_STRIDE) { - if (this.atomCache[i] == key) { - return i; - } - } - - return NOT_FOUND; - } - - public int allocateNewEntry(Atom key) { - int newKeyIndex = this.nextKey; - this.nextKey += ENTRY_STRIDE; - int newValueIndex = newKeyIndex + 1; - int currentSize = this.atomCache.length; - if (newValueIndex >= currentSize) { - int newSize = MiscUtils.growByHalf(currentSize, newValueIndex + 1); - Object[] newCache = new Object[newSize]; - System.arraycopy(this.atomCache, 0, newCache, 0, currentSize); - this.atomCache = newCache; - } - - this.atomCache[newKeyIndex] = key; - return newKeyIndex; - } - - @Nullable - public CacheEntry getValue(int keyIndex) { - return (CacheEntry) this.atomCache[keyIndex + 1]; - } - - public void setValue(int keyIndex, CacheEntry entry) { - this.atomCache[keyIndex + 1] = entry; - } - } - - class Silent implements ParseState { - private final ErrorCollector silentCollector = new ErrorCollector.Nop<>(); - - @Override - public ErrorCollector errorCollector() { - return this.silentCollector; - } - - @Override - public Scope scope() { - return CachedParseState.this.scope(); - } - - @Nullable - @Override - public T parse(NamedRule rule) { - return CachedParseState.this.parse(rule); - } - - @Override - public S input() { - return CachedParseState.this.input(); - } - - @Override - public int mark() { - return CachedParseState.this.mark(); - } - - @Override - public void restore(int mark) { - CachedParseState.this.restore(mark); - } - - @Override - public Control acquireControl() { - return CachedParseState.this.acquireControl(); - } - - @Override - public void releaseControl() { - CachedParseState.this.releaseControl(); - } - - @Override - public ParseState silent() { - return this; - } - } - - static class SimpleControl implements Control { - private boolean hasCut; - - @Override - public void cut() { - this.hasCut = true; - } - - @Override - public boolean hasCut() { - return this.hasCut; - } - - public void reset() { - this.hasCut = false; - } - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/Control.java b/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/Control.java deleted file mode 100644 index b17ce13ec..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/Control.java +++ /dev/null @@ -1,18 +0,0 @@ -package net.momirealms.craftengine.core.util.snbt.parse; - -public interface Control { - Control UNBOUND = new Control() { - @Override - public void cut() { - } - - @Override - public boolean hasCut() { - return false; - } - }; - - void cut(); - - boolean hasCut(); -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/DelayedException.java b/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/DelayedException.java deleted file mode 100644 index 173b85840..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/DelayedException.java +++ /dev/null @@ -1,19 +0,0 @@ -package net.momirealms.craftengine.core.util.snbt.parse; - -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; -import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; -import net.momirealms.craftengine.core.util.snbt.parse.grammar.StringReaderTerms; - -@FunctionalInterface -public interface DelayedException { - T create(String contents, int position); - - static DelayedException create(SimpleCommandExceptionType type) { - return (contents, position) -> type.createWithContext(StringReaderTerms.createReader(contents, position)); - } - - static DelayedException create(DynamicCommandExceptionType type, String argument) { - return (contents, position) -> type.createWithContext(StringReaderTerms.createReader(contents, position), argument); - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/Dictionary.java b/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/Dictionary.java deleted file mode 100644 index 66ea4e088..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/Dictionary.java +++ /dev/null @@ -1,93 +0,0 @@ -package net.momirealms.craftengine.core.util.snbt.parse; - -import javax.annotation.Nullable; -import java.util.IdentityHashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.function.Supplier; - -@SuppressWarnings("unchecked") -public class Dictionary { - private final Map, Entry> terms = new IdentityHashMap<>(); - - public NamedRule put(Atom name, Rule entry) { - Entry holder = (Entry)this.terms.computeIfAbsent(name, Entry::new); - if (holder.value != null) { - throw new IllegalArgumentException("Trying to override rule: " + name); - } - holder.value = entry; - return holder; - } - - public NamedRule putComplex(Atom name, Term term, Rule.RuleAction action) { - return this.put(name, Rule.fromTerm(term, action)); - } - - public NamedRule put(Atom name, Term term, Rule.SimpleRuleAction action) { - return this.put(name, Rule.fromTerm(term, action)); - } - - public void checkAllBound() { - List> unboundNames = this.terms.entrySet().stream() - .filter(entry -> entry.getValue() == null) - .map(Map.Entry::getKey) - .toList(); - if (!unboundNames.isEmpty()) { - throw new IllegalStateException("Unbound names: " + unboundNames); - } - } - - public NamedRule forward(Atom name) { - return this.getOrCreateEntry(name); - } - - private Entry getOrCreateEntry(Atom name) { - return (Entry)this.terms.computeIfAbsent(name, Entry::new); - } - - public Term named(Atom name) { - return new Reference<>(this.getOrCreateEntry(name), name); - } - - public Term namedWithAlias(Atom nameToParse, Atom nameToStore) { - return new Reference<>(this.getOrCreateEntry(nameToParse), nameToStore); - } - - static class Entry implements NamedRule, Supplier { - private final Atom name; - @Nullable - Rule value; - - private Entry(Atom name) { - this.name = name; - } - - @Override - public Atom name() { - return this.name; - } - - @Override - public Rule value() { - return Objects.requireNonNull(this.value, this); - } - - @Override - public String get() { - return "Unbound rule " + this.name; - } - } - - record Reference(Entry ruleToParse, Atom nameToStore) implements Term { - @Override - public boolean parse(ParseState state, Scope scope, Control control) { - T result = state.parse(this.ruleToParse); - if (result == null) { - return false; - } - scope.put(this.nameToStore, result); - return true; - } - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/ErrorCollector.java b/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/ErrorCollector.java deleted file mode 100644 index 1bb43a0ae..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/ErrorCollector.java +++ /dev/null @@ -1,97 +0,0 @@ -package net.momirealms.craftengine.core.util.snbt.parse; - -import net.momirealms.craftengine.core.util.MiscUtils; - -import java.util.ArrayList; -import java.util.List; - -@SuppressWarnings("unchecked") -public interface ErrorCollector { - void store(int cursor, SuggestionSupplier suggestions, Object reason); - - default void store(int cursor, Object reason) { - this.store(cursor, SuggestionSupplier.empty(), reason); - } - - void finish(int finalCursor); - - class LongestOnly implements ErrorCollector { - private MutableErrorEntry[] entries = new MutableErrorEntry[16]; - private int nextErrorEntry; - private int lastCursor = -1; - - private void discardErrorsFromShorterParse(int cursor) { - if (cursor > this.lastCursor) { - this.lastCursor = cursor; - this.nextErrorEntry = 0; - } - } - - @Override - public void finish(int finalCursor) { - this.discardErrorsFromShorterParse(finalCursor); - } - - @Override - public void store(int cursor, SuggestionSupplier suggestions, Object reason) { - this.discardErrorsFromShorterParse(cursor); - if (cursor == this.lastCursor) { - this.addErrorEntry(suggestions, reason); - } - } - - private void addErrorEntry(SuggestionSupplier suggestions, Object reason) { - int currentSize = this.entries.length; - if (this.nextErrorEntry >= currentSize) { - int newSize = MiscUtils.growByHalf(currentSize, this.nextErrorEntry + 1); - MutableErrorEntry[] newEntries = new MutableErrorEntry[newSize]; - System.arraycopy(this.entries, 0, newEntries, 0, currentSize); - this.entries = newEntries; - } - - int entryIndex = this.nextErrorEntry++; - MutableErrorEntry entry = this.entries[entryIndex]; - if (entry == null) { - entry = new MutableErrorEntry<>(); - this.entries[entryIndex] = entry; - } - - entry.suggestions = suggestions; - entry.reason = reason; - } - - public List> entries() { - int errorCount = this.nextErrorEntry; - if (errorCount == 0) { - return List.of(); - } - List> result = new ArrayList<>(errorCount); - - for (int i = 0; i < errorCount; i++) { - MutableErrorEntry mutableErrorEntry = this.entries[i]; - result.add(new ErrorEntry<>(this.lastCursor, mutableErrorEntry.suggestions, mutableErrorEntry.reason)); - } - - return result; - } - - public int cursor() { - return this.lastCursor; - } - - static class MutableErrorEntry { - SuggestionSupplier suggestions = SuggestionSupplier.empty(); - Object reason = "empty"; - } - } - - class Nop implements ErrorCollector { - @Override - public void store(int cursor, SuggestionSupplier suggestions, Object reason) { - } - - @Override - public void finish(int finalCursor) { - } - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/ErrorEntry.java b/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/ErrorEntry.java deleted file mode 100644 index dff487beb..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/ErrorEntry.java +++ /dev/null @@ -1,4 +0,0 @@ -package net.momirealms.craftengine.core.util.snbt.parse; - -public record ErrorEntry(int cursor, SuggestionSupplier suggestions, Object reason) { -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/LocalizedCommandSyntaxException.java b/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/LocalizedCommandSyntaxException.java deleted file mode 100644 index 21204ec40..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/LocalizedCommandSyntaxException.java +++ /dev/null @@ -1,84 +0,0 @@ -package net.momirealms.craftengine.core.util.snbt.parse; - -import com.mojang.brigadier.Message; -import com.mojang.brigadier.exceptions.CommandExceptionType; -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import net.momirealms.craftengine.core.plugin.locale.TranslationManager; -import net.momirealms.craftengine.core.util.AdventureHelper; - -import java.util.Optional; -import java.util.function.Supplier; - -public class LocalizedCommandSyntaxException extends CommandSyntaxException { - 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 HERE_NODE = "warning.config.type.snbt.invalid_syntax.here"; - private final Message message; - private final String input; - private final int cursor; - - public LocalizedCommandSyntaxException(CommandExceptionType type, Message message) { - super(type, message); - this.message = message; - this.input = null; - this.cursor = -1; - } - - public LocalizedCommandSyntaxException(CommandExceptionType type, Message message, String input, int cursor) { - super(type, message, input, cursor); - this.message = message; - this.input = input; - this.cursor = cursor; - } - - @Override - public String getMessage() { - String message = this.message.getString(); - final String context = getContext(); - if (context == null) { - return message; - } - return generateLocalizedMessage( - PARSE_ERROR_NODE, - () -> message + " at position " + this.cursor + ": " + context, - message, String.valueOf(this.cursor), context - ); - } - - @Override - public String getContext() { - if (this.input == null || this.cursor < 0) { - return null; - } - final StringBuilder builder = new StringBuilder(); - final int cursor = Math.min(this.input.length(), this.cursor); - - if (cursor > CONTEXT_AMOUNT) { - builder.append("..."); - } - - builder.append(this.input, Math.max(0, cursor - CONTEXT_AMOUNT), cursor); - builder.append(generateLocalizedMessage(HERE_NODE, () -> "<--[HERE]")); - - return builder.toString(); - } - - - private String generateLocalizedMessage(String node, Supplier fallback, String... arguments) { - try { - String rawMessage = Optional.ofNullable(TranslationManager.instance() - .miniMessageTranslation(node)).orElse(fallback.get()); - String cleanMessage = AdventureHelper.miniMessage() - .stripTags(rawMessage); - for (int i = 0; i < arguments.length; i++) { - cleanMessage = cleanMessage.replace( - "", - arguments[i] != null ? arguments[i] : "null" - ); - } - return cleanMessage; - } catch (Exception e) { - return fallback.get(); - } - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/LocalizedDynamicCommandExceptionType.java b/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/LocalizedDynamicCommandExceptionType.java deleted file mode 100644 index 99dde080a..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/LocalizedDynamicCommandExceptionType.java +++ /dev/null @@ -1,27 +0,0 @@ -package net.momirealms.craftengine.core.util.snbt.parse; - -import com.mojang.brigadier.ImmutableStringReader; -import com.mojang.brigadier.Message; -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; - -import java.util.function.Function; - -public class LocalizedDynamicCommandExceptionType extends DynamicCommandExceptionType { - private final Function function; - - public LocalizedDynamicCommandExceptionType(Function function) { - super(function); - this.function = function; - } - - @Override - public CommandSyntaxException create(final Object arg) { - return new LocalizedCommandSyntaxException(this, function.apply(arg)); - } - - @Override - public CommandSyntaxException createWithContext(final ImmutableStringReader reader, final Object arg) { - return new LocalizedCommandSyntaxException(this, function.apply(arg), reader.getString(), reader.getCursor()); - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/LocalizedMessage.java b/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/LocalizedMessage.java deleted file mode 100644 index c8da1cab7..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/LocalizedMessage.java +++ /dev/null @@ -1,53 +0,0 @@ -package net.momirealms.craftengine.core.util.snbt.parse; - -import com.mojang.brigadier.Message; -import net.momirealms.craftengine.core.plugin.locale.TranslationManager; -import net.momirealms.craftengine.core.util.AdventureHelper; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Arrays; -import java.util.Optional; - -public class LocalizedMessage implements Message { - private final String node; - private final String[] arguments; - - public LocalizedMessage( - @NotNull String node, - @Nullable String... arguments - ) { - this.node = node; - this.arguments = arguments != null - ? Arrays.copyOf(arguments, arguments.length) - : new String[0]; - } - - @Override - public String getString() { - return generateLocalizedMessage(); - } - - private String generateLocalizedMessage() { - try { - String rawMessage = Optional.ofNullable(TranslationManager.instance() - .miniMessageTranslation(this.node)).orElse(this.node); - String cleanMessage = AdventureHelper.miniMessage() - .stripTags(rawMessage); - for (int i = 0; i < arguments.length; i++) { - cleanMessage = cleanMessage.replace( - "", - arguments[i] != null ? arguments[i] : "null" - ); - } - return cleanMessage; - } catch (Exception e) { - return String.format( - "Failed to translate. Node: %s, Arguments: %s. Cause: %s", - node, - Arrays.toString(arguments), - e.getMessage() - ); - } - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/LocalizedSimpleCommandExceptionType.java b/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/LocalizedSimpleCommandExceptionType.java deleted file mode 100644 index b046fab0c..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/LocalizedSimpleCommandExceptionType.java +++ /dev/null @@ -1,25 +0,0 @@ -package net.momirealms.craftengine.core.util.snbt.parse; - -import com.mojang.brigadier.ImmutableStringReader; -import com.mojang.brigadier.Message; -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; - -public class LocalizedSimpleCommandExceptionType extends SimpleCommandExceptionType { - private final Message message; - - public LocalizedSimpleCommandExceptionType(Message message) { - super(message); - this.message = message; - } - - @Override - public CommandSyntaxException create() { - return new LocalizedCommandSyntaxException(this, message); - } - - @Override - public CommandSyntaxException createWithContext(final ImmutableStringReader reader) { - return new LocalizedCommandSyntaxException(this, message, reader.getString(), reader.getCursor()); - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/NamedRule.java b/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/NamedRule.java deleted file mode 100644 index d4f634e1d..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/NamedRule.java +++ /dev/null @@ -1,7 +0,0 @@ -package net.momirealms.craftengine.core.util.snbt.parse; - -public interface NamedRule { - Atom name(); - - Rule value(); -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/ParseState.java b/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/ParseState.java deleted file mode 100644 index 2ab971364..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/ParseState.java +++ /dev/null @@ -1,37 +0,0 @@ -package net.momirealms.craftengine.core.util.snbt.parse; - -import javax.annotation.Nullable; -import java.util.Optional; - -public interface ParseState { - Scope scope(); - - ErrorCollector errorCollector(); - - default Optional parseTopRule(NamedRule rule) { - T result = this.parse(rule); - if (result != null) { - this.errorCollector().finish(this.mark()); - } - - if (!this.scope().hasOnlySingleFrame()) { - throw new IllegalStateException("Malformed scope: " + this.scope()); - } - return Optional.ofNullable(result); - } - - @Nullable - T parse(NamedRule rule); - - S input(); - - int mark(); - - void restore(int mark); - - Control acquireControl(); - - void releaseControl(); - - ParseState silent(); -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/Rule.java b/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/Rule.java deleted file mode 100644 index cfb7403c4..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/Rule.java +++ /dev/null @@ -1,51 +0,0 @@ -package net.momirealms.craftengine.core.util.snbt.parse; - -import javax.annotation.Nullable; - -public interface Rule { - @Nullable - T parse(ParseState state); - - static Rule fromTerm(Term child, RuleAction action) { - return new WrappedTerm<>(action, child); - } - - static Rule fromTerm(Term child, SimpleRuleAction action) { - return new WrappedTerm<>(action, child); - } - - @FunctionalInterface - interface RuleAction { - @Nullable - T run(ParseState state); - } - - @FunctionalInterface - interface SimpleRuleAction extends RuleAction { - T run(Scope ruleScope); - - @Override - default T run(ParseState state) { - return this.run(state.scope()); - } - } - - record WrappedTerm(RuleAction action, Term child) implements Rule { - @Nullable - @Override - public T parse(ParseState state) { - Scope scope = state.scope(); - scope.pushFrame(); - - try { - if (!this.child.parse(state, scope, Control.UNBOUND)) { - return null; - } - - return this.action.run(state); - } finally { - scope.popFrame(); - } - } - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/Scope.java b/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/Scope.java deleted file mode 100644 index d152ecc89..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/Scope.java +++ /dev/null @@ -1,315 +0,0 @@ -package net.momirealms.craftengine.core.util.snbt.parse; - -import com.google.common.annotations.VisibleForTesting; -import net.momirealms.craftengine.core.util.MiscUtils; - -import javax.annotation.Nullable; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; - -@SuppressWarnings("unchecked") -public final class Scope { - private static final int NOT_FOUND = -1; - private static final Object FRAME_START_MARKER = new Object() { - @Override - public String toString() { - return "frame"; - } - }; - private static final int ENTRY_STRIDE = 2; - private Object[] stack = new Object[128]; - private int topEntryKeyIndex = 0; - private int topMarkerKeyIndex = 0; - private int depth; - - public Scope() { - this.stack[0] = FRAME_START_MARKER; - this.stack[1] = null; - } - - private int valueIndex(Atom atom) { - for (int i = this.topEntryKeyIndex; i > this.topMarkerKeyIndex; i -= ENTRY_STRIDE) { - Object key = this.stack[i]; - - assert key instanceof Atom; - - if (key == atom) { - return i + 1; - } - } - - return NOT_FOUND; - } - - public int valueIndexForAny(Atom... atoms) { - for (int i = this.topEntryKeyIndex; i > this.topMarkerKeyIndex; i -= ENTRY_STRIDE) { - Object key = this.stack[i]; - - assert key instanceof Atom; - - for (Atom atom : atoms) { - if (atom == key) { - return i + 1; - } - } - } - - return NOT_FOUND; - } - - private void ensureCapacity(int additionalEntryCount) { - int currentSize = this.stack.length; - int currentLastValueIndex = this.topEntryKeyIndex + 1; - int newLastValueIndex = currentLastValueIndex + additionalEntryCount * 2; - if (newLastValueIndex >= currentSize) { - int newSize = MiscUtils.growByHalf(currentSize, newLastValueIndex + 1); - Object[] newStack = new Object[newSize]; - System.arraycopy(this.stack, 0, newStack, 0, currentSize); - this.stack = newStack; - } - - assert this.validateStructure(); - } - - private void setupNewFrame() { - this.topEntryKeyIndex += ENTRY_STRIDE; - this.stack[this.topEntryKeyIndex] = FRAME_START_MARKER; - this.stack[this.topEntryKeyIndex + 1] = this.topMarkerKeyIndex; - this.topMarkerKeyIndex = this.topEntryKeyIndex; - } - - public void pushFrame() { - this.ensureCapacity(1); - this.setupNewFrame(); - - assert this.validateStructure(); - } - - private int getPreviousMarkerIndex(int markerKeyIndex) { - return (Integer) this.stack[markerKeyIndex + 1]; - } - - public void popFrame() { - assert this.topMarkerKeyIndex != 0; - - this.topEntryKeyIndex = this.topMarkerKeyIndex - ENTRY_STRIDE; - this.topMarkerKeyIndex = this.getPreviousMarkerIndex(this.topMarkerKeyIndex); - - assert this.validateStructure(); - } - - public void splitFrame() { - int currentFrameMarkerIndex = this.topMarkerKeyIndex; - int nonMarkerEntriesInFrame = (this.topEntryKeyIndex - this.topMarkerKeyIndex) / ENTRY_STRIDE; - this.ensureCapacity(nonMarkerEntriesInFrame + 1); - this.setupNewFrame(); - int sourceCursor = currentFrameMarkerIndex + ENTRY_STRIDE; - int targetCursor = this.topEntryKeyIndex; - - for (int i = 0; i < nonMarkerEntriesInFrame; i++) { - targetCursor += ENTRY_STRIDE; - Object key = this.stack[sourceCursor]; - - assert key != null; - - this.stack[targetCursor] = key; - this.stack[targetCursor + 1] = null; - sourceCursor += ENTRY_STRIDE; - } - - this.topEntryKeyIndex = targetCursor; - - assert this.validateStructure(); - } - - public void clearFrameValues() { - for (int i = this.topEntryKeyIndex; i > this.topMarkerKeyIndex; i -= ENTRY_STRIDE) { - assert this.stack[i] instanceof Atom; - - this.stack[i + 1] = null; - } - - assert this.validateStructure(); - } - - public void mergeFrame() { - int previousMarkerIndex = this.getPreviousMarkerIndex(this.topMarkerKeyIndex); - int previousFrameCursor = previousMarkerIndex; - int currentFrameCursor = this.topMarkerKeyIndex; - - while (currentFrameCursor < this.topEntryKeyIndex) { - previousFrameCursor += ENTRY_STRIDE; - currentFrameCursor += ENTRY_STRIDE; - Object newKey = this.stack[currentFrameCursor]; - - assert newKey instanceof Atom; - - Object newValue = this.stack[currentFrameCursor + 1]; - Object oldKey = this.stack[previousFrameCursor]; - if (oldKey != newKey) { - this.stack[previousFrameCursor] = newKey; - this.stack[previousFrameCursor + 1] = newValue; - } else if (newValue != null) { - this.stack[previousFrameCursor + 1] = newValue; - } - } - - this.topEntryKeyIndex = previousFrameCursor; - this.topMarkerKeyIndex = previousMarkerIndex; - - assert this.validateStructure(); - } - - public void put(Atom name, @Nullable T value) { - int valueIndex = this.valueIndex(name); - if (valueIndex != NOT_FOUND) { - this.stack[valueIndex] = value; - } else { - this.ensureCapacity(1); - this.topEntryKeyIndex += ENTRY_STRIDE; - this.stack[this.topEntryKeyIndex] = name; - this.stack[this.topEntryKeyIndex + 1] = value; - } - - assert this.validateStructure(); - } - - @Nullable - public T get(Atom name) { - int valueIndex = this.valueIndex(name); - return (T) (valueIndex != NOT_FOUND ? this.stack[valueIndex] : null); - } - - public T getOrThrow(Atom name) { - int valueIndex = this.valueIndex(name); - if (valueIndex == NOT_FOUND) { - throw new IllegalArgumentException("No value for atom " + name); - } - return (T) this.stack[valueIndex]; - } - - public T getOrDefault(Atom name, T fallback) { - int valueIndex = this.valueIndex(name); - return (T) (valueIndex != NOT_FOUND ? this.stack[valueIndex] : fallback); - } - - @Nullable - @SafeVarargs - public final T getAny(Atom... names) { - int valueIndex = this.valueIndexForAny(names); - return (T) (valueIndex != NOT_FOUND ? this.stack[valueIndex] : null); - } - - @SafeVarargs - public final T getAnyOrThrow(Atom... names) { - int valueIndex = this.valueIndexForAny(names); - if (valueIndex == NOT_FOUND) { - throw new IllegalArgumentException("No value for atoms " + Arrays.toString(names)); - } - return (T) this.stack[valueIndex]; - } - - @Override - public String toString() { - StringBuilder result = new StringBuilder(); - boolean afterFrame = true; - - for (int i = 0; i <= this.topEntryKeyIndex; i += ENTRY_STRIDE) { - Object key = this.stack[i]; - Object value = this.stack[i + 1]; - if (key == FRAME_START_MARKER) { - result.append('|'); - afterFrame = true; - } else { - if (!afterFrame) { - result.append(','); - } - - afterFrame = false; - result.append(key).append(':').append(value); - } - } - - return result.toString(); - } - - @VisibleForTesting - public Map, ?> lastFrame() { - HashMap, Object> result = new HashMap<>(); - - for (int i = this.topEntryKeyIndex; i > this.topMarkerKeyIndex; i -= ENTRY_STRIDE) { - Object key = this.stack[i]; - Object value = this.stack[i + 1]; - result.put((Atom) key, value); - } - - return result; - } - - public boolean hasOnlySingleFrame() { - for (int i = this.topEntryKeyIndex; i > 0; i--) { - if (this.stack[i] == FRAME_START_MARKER) { - return false; - } - } - - if (this.stack[0] != FRAME_START_MARKER) { - throw new IllegalStateException("Corrupted stack"); - } - return true; - } - - private boolean validateStructure() { - assert this.topMarkerKeyIndex >= 0; - - assert this.topEntryKeyIndex >= this.topMarkerKeyIndex; - - for (int i = 0; i <= this.topEntryKeyIndex; i += ENTRY_STRIDE) { - Object object = this.stack[i]; - if (object != FRAME_START_MARKER && !(object instanceof Atom)) { - return false; - } - } - - for (int ix = this.topMarkerKeyIndex; ix != 0; ix = this.getPreviousMarkerIndex(ix)) { - Object object = this.stack[ix]; - if (object != FRAME_START_MARKER) { - return false; - } - } - - return true; - } - - @SuppressWarnings({"unchecked", "rawtypes"}) - public static Term increaseDepth() { - class IncreasingDepthTerm implements Term { - public static final IncreasingDepthTerm INSTANCE = new IncreasingDepthTerm(); - - @Override - public boolean parse(final ParseState state, final Scope scope, final Control control) { - if (++scope.depth > 512) { - state.errorCollector().store(state.mark(), new IllegalStateException("Too deep")); - return false; - } - return true; - } - } - return (Term) IncreasingDepthTerm.INSTANCE; - } - - @SuppressWarnings({"unchecked", "rawtypes"}) - public static Term decreaseDepth() { - class DecreasingDepthTerm implements Term { - public static final DecreasingDepthTerm INSTANCE = new DecreasingDepthTerm(); - - @Override - public boolean parse(final ParseState state, final Scope scope, final Control control) { - scope.depth--; - return true; - } - } - return (Term) DecreasingDepthTerm.INSTANCE; - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/SuggestionSupplier.java b/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/SuggestionSupplier.java deleted file mode 100644 index 30c32ac7c..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/SuggestionSupplier.java +++ /dev/null @@ -1,11 +0,0 @@ -package net.momirealms.craftengine.core.util.snbt.parse; - -import java.util.stream.Stream; - -public interface SuggestionSupplier { - Stream possibleValues(ParseState state); - - static SuggestionSupplier empty() { - return state -> Stream.empty(); - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/Term.java b/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/Term.java deleted file mode 100644 index 383602b0e..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/Term.java +++ /dev/null @@ -1,235 +0,0 @@ -package net.momirealms.craftengine.core.util.snbt.parse; - -import java.util.ArrayList; -import java.util.List; - -public interface Term { - boolean parse(ParseState state, Scope scope, Control control); - - static Term marker(Atom name, T value) { - return new Marker<>(name, value); - } - - @SafeVarargs - static Term sequence(Term... terms) { - return new Sequence<>(terms); - } - - @SafeVarargs - static Term alternative(Term... terms) { - return new Alternative<>(terms); - } - - static Term optional(Term term) { - return new Maybe<>(term); - } - - static Term repeated(NamedRule element, Atom> listName) { - return repeated(element, listName, 0); - } - - static Term repeated(NamedRule element, Atom> listName, int minRepetitions) { - return new Repeated<>(element, listName, minRepetitions); - } - - static Term repeatedWithTrailingSeparator(NamedRule element, Atom> listName, Term separator) { - return repeatedWithTrailingSeparator(element, listName, separator, 0); - } - - static Term repeatedWithTrailingSeparator(NamedRule element, Atom> listName, Term seperator, int minRepetitions) { - return new RepeatedWithSeparator<>(element, listName, seperator, minRepetitions, true); - } - - static Term positiveLookahead(Term term) { - return new LookAhead<>(term, true); - } - - static Term cut() { - return new Term<>() { - @Override - public boolean parse(ParseState state, Scope scope, Control control) { - control.cut(); - return true; - } - - @Override - public String toString() { - return "↑"; - } - }; - } - - static Term empty() { - return new Term<>() { - @Override - public boolean parse(ParseState state, Scope scope, Control control) { - return true; - } - - @Override - public String toString() { - return "ε"; - } - }; - } - - static Term fail(final Object message) { - return new Term<>() { - @Override - public boolean parse(ParseState state, Scope scope, Control control) { - state.errorCollector().store(state.mark(), message); - return false; - } - - @Override - public String toString() { - return "fail"; - } - }; - } - - record Alternative(Term[] elements) implements Term { - @Override - public boolean parse(ParseState state, Scope scope, Control control) { - Control controlForThis = state.acquireControl(); - - try { - int mark = state.mark(); - scope.splitFrame(); - - for (Term element : this.elements) { - if (element.parse(state, scope, controlForThis)) { - scope.mergeFrame(); - return true; - } - - scope.clearFrameValues(); - state.restore(mark); - if (controlForThis.hasCut()) { - break; - } - } - - scope.popFrame(); - return false; - } finally { - state.releaseControl(); - } - } - } - - record LookAhead(Term term, boolean positive) implements Term { - @Override - public boolean parse(ParseState state, Scope scope, Control control) { - int mark = state.mark(); - boolean result = this.term.parse(state.silent(), scope, control); - state.restore(mark); - return this.positive == result; - } - } - - record Marker(Atom name, T value) implements Term { - @Override - public boolean parse(ParseState state, Scope scope, Control control) { - scope.put(this.name, this.value); - return true; - } - } - - record Maybe(Term term) implements Term { - @Override - public boolean parse(ParseState state, Scope scope, Control control) { - int mark = state.mark(); - if (!this.term.parse(state, scope, control)) { - state.restore(mark); - } - - return true; - } - } - - record Repeated(NamedRule element, Atom> listName, int minRepetitions) implements Term { - @Override - public boolean parse(ParseState state, Scope scope, Control control) { - int mark = state.mark(); - List elements = new ArrayList<>(this.minRepetitions); - - while (true) { - int entryMark = state.mark(); - T parsedElement = state.parse(this.element); - if (parsedElement == null) { - state.restore(entryMark); - if (elements.size() < this.minRepetitions) { - state.restore(mark); - return false; - } - scope.put(this.listName, elements); - return true; - } - - elements.add(parsedElement); - } - } - } - - record RepeatedWithSeparator( - NamedRule element, Atom> listName, Term separator, int minRepetitions, boolean allowTrailingSeparator - ) implements Term { - @Override - public boolean parse(ParseState state, Scope scope, Control control) { - int listMark = state.mark(); - List elements = new ArrayList<>(this.minRepetitions); - boolean first = true; - - while (true) { - int markBeforeSeparator = state.mark(); - if (!first && !this.separator.parse(state, scope, control)) { - state.restore(markBeforeSeparator); - break; - } - - int markAfterSeparator = state.mark(); - T parsedElement = state.parse(this.element); - if (parsedElement == null) { - if (first) { - state.restore(markAfterSeparator); - } else { - if (!this.allowTrailingSeparator) { - state.restore(listMark); - return false; - } - - state.restore(markAfterSeparator); - } - break; - } - - elements.add(parsedElement); - first = false; - } - - if (elements.size() < this.minRepetitions) { - state.restore(listMark); - return false; - } - scope.put(this.listName, elements); - return true; - } - } - - record Sequence(Term[] elements) implements Term { - @Override - public boolean parse(ParseState state, Scope scope, Control control) { - int mark = state.mark(); - - for (Term element : this.elements) { - if (!element.parse(state, scope, control)) { - state.restore(mark); - return false; - } - } - - return true; - } - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/grammar/Grammar.java b/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/grammar/Grammar.java deleted file mode 100644 index e93117570..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/grammar/Grammar.java +++ /dev/null @@ -1,51 +0,0 @@ -package net.momirealms.craftengine.core.util.snbt.parse.grammar; - -import com.mojang.brigadier.StringReader; -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import net.momirealms.craftengine.core.util.snbt.parse.*; - -import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; - -public record Grammar(Dictionary rules, NamedRule top) { - public Grammar { - rules.checkAllBound(); - } - - public Optional parse(ParseState state) { - return state.parseTopRule(this.top); - } - - public T parse(StringReader reader) throws CommandSyntaxException { - ErrorCollector.LongestOnly errorCollector = new ErrorCollector.LongestOnly<>(); - StringReaderParserState stringReaderParserState = new StringReaderParserState(errorCollector, reader); - Optional optionalResult = this.parse(stringReaderParserState); - if (optionalResult.isPresent()) { - T result = optionalResult.get(); - if (CachedParseState.JAVA_NULL_VALUE_MARKER.equals(result)) { - result = null; - } - return result; - } - List> errorEntries = errorCollector.entries(); - List exceptions = errorEntries.stream().mapMulti((entry, output) -> { - if (entry.reason() instanceof DelayedException delayedException) { - output.accept(delayedException.create(reader.getString(), entry.cursor())); - } else if (entry.reason() instanceof Exception exception1) { - output.accept(exception1); - } - }).toList(); - - for (Exception exception : exceptions) { - if (exception instanceof CommandSyntaxException cse) { - throw cse; - } - } - - if (exceptions.size() == 1 && exceptions.getFirst() instanceof RuntimeException re) { - throw re; - } - throw new IllegalStateException("Failed to parse: " + errorEntries.stream().map(ErrorEntry::toString).collect(Collectors.joining(", "))); - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/grammar/GreedyPatternParseRule.java b/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/grammar/GreedyPatternParseRule.java deleted file mode 100644 index 58bf9d797..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/grammar/GreedyPatternParseRule.java +++ /dev/null @@ -1,33 +0,0 @@ -package net.momirealms.craftengine.core.util.snbt.parse.grammar; - -import com.mojang.brigadier.StringReader; -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import net.momirealms.craftengine.core.util.snbt.parse.DelayedException; -import net.momirealms.craftengine.core.util.snbt.parse.ParseState; -import net.momirealms.craftengine.core.util.snbt.parse.Rule; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public final class GreedyPatternParseRule implements Rule { - private final Pattern pattern; - private final DelayedException error; - - public GreedyPatternParseRule(Pattern pattern, DelayedException error) { - this.pattern = pattern; - this.error = error; - } - - @Override - public String parse(ParseState state) { - StringReader input = state.input(); - String fullString = input.getString(); - Matcher matcher = this.pattern.matcher(fullString).region(input.getCursor(), fullString.length()); - if (!matcher.lookingAt()) { - state.errorCollector().store(state.mark(), this.error); - return null; - } - input.setCursor(matcher.end()); - return matcher.group(0); - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/grammar/GreedyPredicateParseRule.java b/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/grammar/GreedyPredicateParseRule.java deleted file mode 100644 index 3144dcc27..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/grammar/GreedyPredicateParseRule.java +++ /dev/null @@ -1,48 +0,0 @@ -package net.momirealms.craftengine.core.util.snbt.parse.grammar; - -import com.mojang.brigadier.StringReader; -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import net.momirealms.craftengine.core.util.snbt.parse.DelayedException; -import net.momirealms.craftengine.core.util.snbt.parse.ParseState; -import net.momirealms.craftengine.core.util.snbt.parse.Rule; - -import javax.annotation.Nullable; - -public abstract class GreedyPredicateParseRule implements Rule { - private final int minSize; - private final int maxSize; - private final DelayedException error; - - public GreedyPredicateParseRule(int minSize, DelayedException error) { - this(minSize, Integer.MAX_VALUE, error); - } - - public GreedyPredicateParseRule(int minSize, int maxSize, DelayedException error) { - this.minSize = minSize; - this.maxSize = maxSize; - this.error = error; - } - - @Nullable - @Override - public String parse(ParseState state) { - StringReader input = state.input(); - String fullString = input.getString(); - int start = input.getCursor(); - int pos = start; - - while (pos < fullString.length() && this.isAccepted(fullString.charAt(pos)) && pos - start < this.maxSize) { - pos++; - } - - int length = pos - start; - if (length < this.minSize) { - state.errorCollector().store(state.mark(), this.error); - return null; - } - input.setCursor(pos); - return fullString.substring(start, pos); - } - - protected abstract boolean isAccepted(char c); -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/grammar/NumberRunParseRule.java b/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/grammar/NumberRunParseRule.java deleted file mode 100644 index dd4e6249b..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/grammar/NumberRunParseRule.java +++ /dev/null @@ -1,46 +0,0 @@ -package net.momirealms.craftengine.core.util.snbt.parse.grammar; - -import com.mojang.brigadier.StringReader; -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import net.momirealms.craftengine.core.util.snbt.parse.DelayedException; -import net.momirealms.craftengine.core.util.snbt.parse.ParseState; -import net.momirealms.craftengine.core.util.snbt.parse.Rule; - -import javax.annotation.Nullable; - -public abstract class NumberRunParseRule implements Rule { - private final DelayedException noValueError; - private final DelayedException underscoreNotAllowedError; - - public NumberRunParseRule(DelayedException noValueError, DelayedException underscoreNotAllowedError) { - this.noValueError = noValueError; - this.underscoreNotAllowedError = underscoreNotAllowedError; - } - - @Nullable - @Override - public String parse(ParseState state) { - StringReader input = state.input(); - input.skipWhitespace(); - String fullString = input.getString(); - int start = input.getCursor(); - int pos = start; - - while (pos < fullString.length() && this.isAccepted(fullString.charAt(pos))) { - pos++; - } - - int length = pos - start; - if (length == 0) { - state.errorCollector().store(state.mark(), this.noValueError); - return null; - } else if (fullString.charAt(start) != '_' && fullString.charAt(pos - 1) != '_') { - input.setCursor(pos); - return fullString.substring(start, pos); - } - state.errorCollector().store(state.mark(), this.underscoreNotAllowedError); - return null; - } - - protected abstract boolean isAccepted(char c); -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/grammar/StringReaderParserState.java b/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/grammar/StringReaderParserState.java deleted file mode 100644 index d076fafd4..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/grammar/StringReaderParserState.java +++ /dev/null @@ -1,29 +0,0 @@ -package net.momirealms.craftengine.core.util.snbt.parse.grammar; - -import com.mojang.brigadier.StringReader; -import net.momirealms.craftengine.core.util.snbt.parse.CachedParseState; -import net.momirealms.craftengine.core.util.snbt.parse.ErrorCollector; - -public class StringReaderParserState extends CachedParseState { - private final StringReader input; - - public StringReaderParserState(ErrorCollector errorCollector, StringReader input) { - super(errorCollector); - this.input = input; - } - - @Override - public StringReader input() { - return this.input; - } - - @Override - public int mark() { - return this.input.getCursor(); - } - - @Override - public void restore(int mark) { - this.input.setCursor(mark); - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/grammar/StringReaderTerms.java b/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/grammar/StringReaderTerms.java deleted file mode 100644 index 14fe3f3aa..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/grammar/StringReaderTerms.java +++ /dev/null @@ -1,64 +0,0 @@ -package net.momirealms.craftengine.core.util.snbt.parse.grammar; - -import com.mojang.brigadier.StringReader; -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; -import it.unimi.dsi.fastutil.chars.CharList; -import net.momirealms.craftengine.core.util.snbt.parse.*; - -import java.util.stream.Collectors; - -public interface StringReaderTerms { - DynamicCommandExceptionType LITERAL_INCORRECT = new LocalizedDynamicCommandExceptionType( - expected -> new LocalizedMessage("warning.config.type.snbt.parser.incorrect", String.valueOf(expected)) - ); - - static Term character(final char value) { - return new TerminalCharacters(CharList.of(value)) { - @Override - protected boolean isAccepted(char v) { - return value == v; - } - }; - } - - static Term characters(final char v1, final char v2) { - return new TerminalCharacters(CharList.of(v1, v2)) { - @Override - protected boolean isAccepted(char v) { - return v == v1 || v == v2; - } - }; - } - - static StringReader createReader(String contents, int cursor) { - StringReader reader = new StringReader(contents); - reader.setCursor(cursor); - return reader; - } - - abstract class TerminalCharacters implements Term { - private final DelayedException error; - private final SuggestionSupplier suggestions; - - public TerminalCharacters(CharList values) { - String joinedValues = values.intStream().mapToObj(Character::toString).collect(Collectors.joining("|")); - this.error = DelayedException.create(LITERAL_INCORRECT, joinedValues); - this.suggestions = s -> values.intStream().mapToObj(Character::toString); - } - - @Override - public boolean parse(ParseState state, Scope scope, Control control) { - state.input().skipWhitespace(); - int cursor = state.mark(); - if (state.input().canRead() && this.isAccepted(state.input().read())) { - return true; - } - state.errorCollector().store(cursor, this.suggestions, this.error); - return false; - } - - protected abstract boolean isAccepted(char value); - } - -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/grammar/UnquotedStringParseRule.java b/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/grammar/UnquotedStringParseRule.java deleted file mode 100644 index 2d46092b7..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/util/snbt/parse/grammar/UnquotedStringParseRule.java +++ /dev/null @@ -1,32 +0,0 @@ -package net.momirealms.craftengine.core.util.snbt.parse.grammar; - -import com.mojang.brigadier.StringReader; -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import net.momirealms.craftengine.core.util.snbt.parse.DelayedException; -import net.momirealms.craftengine.core.util.snbt.parse.ParseState; -import net.momirealms.craftengine.core.util.snbt.parse.Rule; - -import javax.annotation.Nullable; - -public class UnquotedStringParseRule implements Rule { - private final int minSize; - private final DelayedException error; - - public UnquotedStringParseRule(int minSize, DelayedException error) { - this.minSize = minSize; - this.error = error; - } - - @Nullable - @Override - public String parse(ParseState state) { - state.input().skipWhitespace(); - int cursor = state.mark(); - String value = state.input().readUnquotedString(); - if (value.length() < this.minSize) { - state.errorCollector().store(cursor, this.error); - return null; - } - return value; - } -} diff --git a/gradle.properties b/gradle.properties index 95c1bf9cc..1b2eee6a6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -38,7 +38,7 @@ zstd_version=1.5.7-6 commons_io_version=2.21.0 commons_lang3_version=3.20.0 sparrow_nbt_version=0.10.6 -sparrow_util_version=0.66 +sparrow_util_version=0.67 fastutil_version=8.5.18 netty_version=4.1.128.Final joml_version=1.10.8