Optimized parsing
This commit is contained in:
parent
8ed8f02bee
commit
8d4d3cba80
5 changed files with 65 additions and 32 deletions
|
@ -3,7 +3,7 @@ import groovy.io.FileType
|
|||
apply plugin: 'java-library'
|
||||
apply plugin: 'maven'
|
||||
|
||||
version = '0.1.17'
|
||||
version = '0.1.18'
|
||||
group = 'com.mojang'
|
||||
|
||||
task wrapper(type: Wrapper) {
|
||||
|
|
|
@ -17,10 +17,10 @@ import com.mojang.brigadier.tree.CommandNode;
|
|||
import com.mojang.brigadier.tree.LiteralCommandNode;
|
||||
import com.mojang.brigadier.tree.RootCommandNode;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
@ -170,11 +170,11 @@ public class CommandDispatcher<S> {
|
|||
|
||||
private ParseResults<S> parseNodes(final CommandNode<S> node, final StringReader originalReader, final CommandContextBuilder<S> contextSoFar) {
|
||||
final S source = contextSoFar.getSource();
|
||||
final Map<CommandNode<S>, CommandSyntaxException> errors = Maps.newLinkedHashMap();
|
||||
Map<CommandNode<S>, CommandSyntaxException> errors = null;
|
||||
final List<PartialParse<S>> potentials = Lists.newArrayList();
|
||||
final int cursor = originalReader.getCursor();
|
||||
|
||||
for (final CommandNode<S> child : node.getChildren()) {
|
||||
for (final CommandNode<S> child : node.getRelevantNodes(originalReader)) {
|
||||
if (!child.canUse(source)) {
|
||||
continue;
|
||||
}
|
||||
|
@ -192,6 +192,9 @@ public class CommandDispatcher<S> {
|
|||
}
|
||||
}
|
||||
} catch (final CommandSyntaxException ex) {
|
||||
if (errors == null) {
|
||||
errors = new LinkedHashMap<>();
|
||||
}
|
||||
errors.put(child, ex);
|
||||
reader.setCursor(cursor);
|
||||
continue;
|
||||
|
@ -216,27 +219,32 @@ public class CommandDispatcher<S> {
|
|||
}
|
||||
|
||||
if (!potentials.isEmpty()) {
|
||||
final List<PartialParse<S>> sorted = Lists.newArrayList(potentials);
|
||||
sorted.sort((a, b) -> {
|
||||
if (!a.parse.getReader().canRead() && b.parse.getReader().canRead()) {
|
||||
return -1;
|
||||
}
|
||||
if (a.parse.getReader().canRead() && !b.parse.getReader().canRead()) {
|
||||
return 1;
|
||||
}
|
||||
if (a.parse.getExceptions().isEmpty() && !b.parse.getExceptions().isEmpty()) {
|
||||
return -1;
|
||||
}
|
||||
if (!a.parse.getExceptions().isEmpty() && b.parse.getExceptions().isEmpty()) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
final PartialParse<S> likely = sorted.get(0);
|
||||
final PartialParse<S> likely;
|
||||
if (potentials.size() > 1) {
|
||||
final List<PartialParse<S>> sorted = Lists.newArrayList(potentials);
|
||||
sorted.sort((a, b) -> {
|
||||
if (!a.parse.getReader().canRead() && b.parse.getReader().canRead()) {
|
||||
return -1;
|
||||
}
|
||||
if (a.parse.getReader().canRead() && !b.parse.getReader().canRead()) {
|
||||
return 1;
|
||||
}
|
||||
if (a.parse.getExceptions().isEmpty() && !b.parse.getExceptions().isEmpty()) {
|
||||
return -1;
|
||||
}
|
||||
if (!a.parse.getExceptions().isEmpty() && b.parse.getExceptions().isEmpty()) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
likely = sorted.get(0);
|
||||
} else {
|
||||
likely = potentials.get(0);
|
||||
}
|
||||
return likely.parse;
|
||||
}
|
||||
|
||||
return new ParseResults<>(contextSoFar, originalReader, errors);
|
||||
return new ParseResults<>(contextSoFar, originalReader, errors == null ? Collections.emptyMap() : errors);
|
||||
}
|
||||
|
||||
public String[] getAllUsage(final CommandNode<S> node, final S source, final boolean restricted) {
|
||||
|
|
|
@ -13,6 +13,7 @@ import com.mojang.brigadier.suggestion.Suggestions;
|
|||
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
@ -21,6 +22,8 @@ import java.util.stream.Collectors;
|
|||
|
||||
public abstract class CommandNode<S> implements Comparable<CommandNode<S>> {
|
||||
private Map<String, CommandNode<S>> children = Maps.newLinkedHashMap();
|
||||
private Map<String, LiteralCommandNode<S>> literals = Maps.newLinkedHashMap();
|
||||
private Map<String, ArgumentCommandNode<S, ?>> arguments = Maps.newLinkedHashMap();
|
||||
private final Predicate<S> requirement;
|
||||
private final CommandNode<S> redirect;
|
||||
private final RedirectModifier<S> modifier;
|
||||
|
@ -73,6 +76,11 @@ public abstract class CommandNode<S> implements Comparable<CommandNode<S>> {
|
|||
}
|
||||
} else {
|
||||
children.put(node.getName(), node);
|
||||
if (node instanceof LiteralCommandNode) {
|
||||
literals.put(node.getName(), (LiteralCommandNode<S>) node);
|
||||
} else if (node instanceof ArgumentCommandNode) {
|
||||
arguments.put(node.getName(), (ArgumentCommandNode<S, ?>) node);
|
||||
}
|
||||
}
|
||||
|
||||
children = children.entrySet().stream().sorted(Map.Entry.comparingByValue()).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
|
||||
|
@ -112,6 +120,22 @@ public abstract class CommandNode<S> implements Comparable<CommandNode<S>> {
|
|||
|
||||
protected abstract String getSortedKey();
|
||||
|
||||
public Collection<? extends CommandNode<S>> getRelevantNodes(final StringReader input) {
|
||||
if (literals.size() > 0) {
|
||||
final int cursor = input.getCursor();
|
||||
final String text = input.readUnquotedString();
|
||||
input.setCursor(cursor);
|
||||
final LiteralCommandNode<S> literal = literals.get(text);
|
||||
if (literal != null) {
|
||||
return Collections.singleton(literal);
|
||||
} else {
|
||||
return arguments.values();
|
||||
}
|
||||
} else {
|
||||
return arguments.values();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(final CommandNode<S> o) {
|
||||
return ComparisonChain
|
||||
|
|
|
@ -37,16 +37,17 @@ public class LiteralCommandNode<S> extends CommandNode<S> {
|
|||
@Override
|
||||
public void parse(final StringReader reader, final CommandContextBuilder<S> contextBuilder) throws CommandSyntaxException {
|
||||
final int start = reader.getCursor();
|
||||
for (int i = 0; i < literal.length(); i++) {
|
||||
if (reader.canRead() && reader.peek() == literal.charAt(i)) {
|
||||
reader.skip();
|
||||
} else {
|
||||
reader.setCursor(start);
|
||||
throw ERROR_INCORRECT_LITERAL.createWithContext(reader, literal);
|
||||
if (reader.canRead(literal.length())) {
|
||||
final int end = start + literal.length();
|
||||
if (reader.getString().substring(start, end).equals(literal)) {
|
||||
reader.setCursor(end);
|
||||
contextBuilder.withNode(this, StringRange.between(start, end));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
contextBuilder.withNode(this, StringRange.between(start, reader.getCursor()));
|
||||
reader.setCursor(start);
|
||||
throw ERROR_INCORRECT_LITERAL.createWithContext(reader, literal);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -130,8 +130,8 @@ public class CommandDispatcherTest {
|
|||
subject.execute("foo baz", source);
|
||||
fail();
|
||||
} catch (final CommandSyntaxException ex) {
|
||||
assertThat(ex.getType(), is(LiteralCommandNode.ERROR_INCORRECT_LITERAL));
|
||||
assertThat(ex.getData(), is(Collections.singletonMap("expected", "bar")));
|
||||
assertThat(ex.getType(), is(CommandDispatcher.ERROR_UNKNOWN_ARGUMENT));
|
||||
assertThat(ex.getData(), is(Collections.emptyMap()));
|
||||
assertThat(ex.getCursor(), is(4));
|
||||
}
|
||||
}
|
||||
|
@ -332,7 +332,7 @@ public class CommandDispatcherTest {
|
|||
subject.register(literal("foo").then(argument("bar", integer()).executes(command)));
|
||||
|
||||
try {
|
||||
subject.execute("foo5", source);
|
||||
subject.execute("foo$", source);
|
||||
fail();
|
||||
} catch (final CommandSyntaxException ex) {
|
||||
assertThat(ex.getType(), is(CommandDispatcher.ERROR_EXPECTED_ARGUMENT_SEPARATOR));
|
||||
|
|
Loading…
Reference in a new issue