package net.minecraft.util.parsing.packrat.commands; import com.mojang.brigadier.StringReader; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.suggestion.Suggestions; import com.mojang.brigadier.suggestion.SuggestionsBuilder; import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; import net.minecraft.commands.SharedSuggestionProvider; import net.minecraft.util.parsing.packrat.DelayedException; import net.minecraft.util.parsing.packrat.Dictionary; import net.minecraft.util.parsing.packrat.ErrorCollector; import net.minecraft.util.parsing.packrat.ErrorEntry; import net.minecraft.util.parsing.packrat.NamedRule; import net.minecraft.util.parsing.packrat.ParseState; public record Grammar(Dictionary rules, NamedRule top) implements CommandArgumentParser { public Grammar(Dictionary rules, NamedRule top) { rules.checkAllBound(); this.rules = rules; this.top = top; } public Optional parse(final ParseState state) { return state.parseTopRule(this.top); } @Override public T parseForCommands(final StringReader reader) throws CommandSyntaxException { ErrorCollector.LongestOnly errorCollector = new ErrorCollector.LongestOnly<>(); StringReaderParserState state = new StringReaderParserState(errorCollector, reader); Optional result = this.parse(state); if (result.isPresent()) { return (T)result.get(); } else { 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 exceptionx) { output.accept(exceptionx); } }).toList(); for (Exception exception : exceptions) { if (exception instanceof CommandSyntaxException cse) { throw cse; } } if (exceptions.size() == 1 && exceptions.get(0) instanceof RuntimeException re) { throw re; } else { throw new IllegalStateException("Failed to parse: " + (String)errorEntries.stream().map(ErrorEntry::toString).collect(Collectors.joining(", "))); } } } @Override public CompletableFuture parseForSuggestions(final SuggestionsBuilder suggestionsBuilder) { StringReader reader = new StringReader(suggestionsBuilder.getInput()); reader.setCursor(suggestionsBuilder.getStart()); ErrorCollector.LongestOnly errorCollector = new ErrorCollector.LongestOnly<>(); StringReaderParserState state = new StringReaderParserState(errorCollector, reader); this.parse(state); List> errorEntries = errorCollector.entries(); if (errorEntries.isEmpty()) { return suggestionsBuilder.buildFuture(); } else { SuggestionsBuilder offsetBuilder = suggestionsBuilder.createOffset(errorCollector.cursor()); for (ErrorEntry entry : errorEntries) { if (entry.suggestions() instanceof ResourceSuggestion resourceSuggestionTerm) { SharedSuggestionProvider.suggestResource(resourceSuggestionTerm.possibleResources(), offsetBuilder); } else { SharedSuggestionProvider.suggest(entry.suggestions().possibleValues(state), offsetBuilder); } } return offsetBuilder.buildFuture(); } } }