Improve command parsing logic
This commit is contained in:
parent
b05b428f3c
commit
753ab1dba8
2 changed files with 111 additions and 10 deletions
|
|
@ -24,6 +24,7 @@
|
||||||
package com.intellectualsites.commands;
|
package com.intellectualsites.commands;
|
||||||
|
|
||||||
import com.google.common.base.Objects;
|
import com.google.common.base.Objects;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
import com.intellectualsites.commands.components.CommandComponent;
|
import com.intellectualsites.commands.components.CommandComponent;
|
||||||
import com.intellectualsites.commands.components.StaticComponent;
|
import com.intellectualsites.commands.components.StaticComponent;
|
||||||
import com.intellectualsites.commands.parser.ComponentParseResult;
|
import com.intellectualsites.commands.parser.ComponentParseResult;
|
||||||
|
|
@ -32,6 +33,7 @@ import com.intellectualsites.commands.sender.CommandSender;
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tree containing all commands and command paths
|
* Tree containing all commands and command paths
|
||||||
|
|
@ -62,6 +64,72 @@ public class CommandTree {
|
||||||
|
|
||||||
private Optional<Command> parseCommand(@Nonnull final CommandSender commandSender, @Nonnull final Queue<String> commandQueue,
|
private Optional<Command> parseCommand(@Nonnull final CommandSender commandSender, @Nonnull final Queue<String> commandQueue,
|
||||||
@Nonnull final Node<CommandComponent<?>> root) {
|
@Nonnull final Node<CommandComponent<?>> root) {
|
||||||
|
|
||||||
|
final List<Node<CommandComponent<?>>> children = root.getChildren();
|
||||||
|
if (children.size() == 1 && !(children.get(0).getValue() instanceof StaticComponent)) {
|
||||||
|
// The value has to be a variable
|
||||||
|
final Node<CommandComponent<?>> child = children.get(0);
|
||||||
|
if (child.getValue() != null) {
|
||||||
|
final ComponentParseResult<?> result = child.getValue().getParser().parse(commandSender, commandQueue);
|
||||||
|
if (result.getParsedValue().isPresent()) {
|
||||||
|
/* TODO: Add context */
|
||||||
|
if (child.isLeaf()) {
|
||||||
|
return Optional.ofNullable(child.getValue().getOwningCommand());
|
||||||
|
} else {
|
||||||
|
return this.parseCommand(commandSender, commandQueue, child);
|
||||||
|
}
|
||||||
|
} else if (result.getFailure().isPresent()) {
|
||||||
|
/* TODO: Return error */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* There are 0 or more static components as children. No variable child components are present */
|
||||||
|
if (children.isEmpty()) {
|
||||||
|
/* We are at the bottom. Check if there's a command attached, in which case we're done */
|
||||||
|
if (root.getValue() != null && root.getValue().getOwningCommand() != null) {
|
||||||
|
return Optional.of(root.getValue().getOwningCommand());
|
||||||
|
} else {
|
||||||
|
/* TODO: Indicate that we could not resolve the command here */
|
||||||
|
final List<CommandComponent<?>> components = this.getChain(root).stream().map(Node::getValue).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
final String popped = commandQueue.poll();
|
||||||
|
if (popped == null) {
|
||||||
|
/* Not enough arguments */
|
||||||
|
/* TODO: Send correct usage */
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
int low = 0;
|
||||||
|
int high = children.size() - 1;
|
||||||
|
|
||||||
|
while (low <= high) {
|
||||||
|
int mid = (low + high) / 2;
|
||||||
|
|
||||||
|
final Node<CommandComponent<?>> node = children.get(mid);
|
||||||
|
assert node.getValue() != null;
|
||||||
|
|
||||||
|
final int comparison = node.getValue().getName().compareToIgnoreCase(popped);
|
||||||
|
if (comparison < 0) {
|
||||||
|
low = mid + 1;
|
||||||
|
} else if (comparison > 0) {
|
||||||
|
high = mid - 1;
|
||||||
|
} else {
|
||||||
|
/* We found a match */
|
||||||
|
if (node.isLeaf()) {
|
||||||
|
return Optional.ofNullable(node.getValue().getOwningCommand());
|
||||||
|
} else {
|
||||||
|
return parseCommand(commandSender, commandQueue, node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We could not find a match */
|
||||||
|
/* TODO: Send "No Such Command" */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
final Iterator<Node<CommandComponent<?>>> childIterator = root.getChildren().iterator();
|
final Iterator<Node<CommandComponent<?>>> childIterator = root.getChildren().iterator();
|
||||||
if (childIterator.hasNext()) {
|
if (childIterator.hasNext()) {
|
||||||
while (childIterator.hasNext()) {
|
while (childIterator.hasNext()) {
|
||||||
|
|
@ -69,21 +137,14 @@ public class CommandTree {
|
||||||
if (child.getValue() != null) {
|
if (child.getValue() != null) {
|
||||||
final ComponentParseResult<?> result = child.getValue().getParser().parse(commandSender, commandQueue);
|
final ComponentParseResult<?> result = child.getValue().getParser().parse(commandSender, commandQueue);
|
||||||
if (result.getParsedValue().isPresent()) {
|
if (result.getParsedValue().isPresent()) {
|
||||||
/* TODO: Add to some context */
|
|
||||||
return this.parseCommand(commandSender, commandQueue, child);
|
return this.parseCommand(commandSender, commandQueue, child);
|
||||||
} else if (result.getFailure().isPresent() && root.children.size() == 1) {
|
} else if (result.getFailure().isPresent() && root.children.size() == 1) {
|
||||||
/* Return the error somehow :D */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
/* We are at the bottom. Check if there's a command attached, in which case we're done */
|
|
||||||
if (root.getValue() != null && root.getValue().getOwningCommand() != null) {
|
|
||||||
return Optional.of(root.getValue().getOwningCommand());
|
|
||||||
} else {
|
|
||||||
/* TODO: Indicate that we could not resolve the command here */
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -99,6 +160,9 @@ public class CommandTree {
|
||||||
if (tempNode == null) {
|
if (tempNode == null) {
|
||||||
tempNode = node.addChild(component);
|
tempNode = node.addChild(component);
|
||||||
}
|
}
|
||||||
|
if (node.children.size() > 0) {
|
||||||
|
node.children.sort(Comparator.comparing(Node::getValue));
|
||||||
|
}
|
||||||
node = tempNode;
|
node = tempNode;
|
||||||
}
|
}
|
||||||
if (node.getValue() != null) {
|
if (node.getValue() != null) {
|
||||||
|
|
@ -154,11 +218,22 @@ public class CommandTree {
|
||||||
return leaves;
|
return leaves;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<Node<CommandComponent<?>>> getChain(@Nullable final Node<CommandComponent<?>> end) {
|
||||||
|
final List<Node<CommandComponent<?>>> chain = new LinkedList<>();
|
||||||
|
Node<CommandComponent<?>> tail = end;
|
||||||
|
while (tail != null) {
|
||||||
|
chain.add(tail);
|
||||||
|
tail = end.getParent();
|
||||||
|
}
|
||||||
|
return Lists.reverse(chain);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private static final class Node<T> {
|
private static final class Node<T> {
|
||||||
|
|
||||||
private final List<Node<T>> children = new LinkedList<>();
|
private final List<Node<T>> children = new LinkedList<>();
|
||||||
private final T value;
|
private final T value;
|
||||||
|
private Node<T> parent;
|
||||||
|
|
||||||
private Node(@Nullable final T value) {
|
private Node(@Nullable final T value) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
|
|
@ -208,6 +283,15 @@ public class CommandTree {
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hashCode(getChildren(), getValue());
|
return Objects.hashCode(getChildren(), getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setParent(@Nullable final Node<T> parent) {
|
||||||
|
this.parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable public Node<T> getParent() {
|
||||||
|
return this.parent;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ import java.util.regex.Pattern;
|
||||||
*
|
*
|
||||||
* @param <T> The type that the component parses into
|
* @param <T> The type that the component parses into
|
||||||
*/
|
*/
|
||||||
public class CommandComponent<T> {
|
public class CommandComponent<T> implements Comparable<CommandComponent<?>> {
|
||||||
|
|
||||||
private static final Pattern NAME_PATTERN = Pattern.compile("[A-Za-z0-9]+");
|
private static final Pattern NAME_PATTERN = Pattern.compile("[A-Za-z0-9]+");
|
||||||
|
|
||||||
|
|
@ -152,6 +152,23 @@ public class CommandComponent<T> {
|
||||||
return com.google.common.base.Objects.hashCode(isRequired(), getName());
|
return com.google.common.base.Objects.hashCode(isRequired(), getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(@Nonnull final CommandComponent<?> o) {
|
||||||
|
if (this instanceof StaticComponent) {
|
||||||
|
if (o instanceof StaticComponent) {
|
||||||
|
return (this.getName().compareTo(o.getName()));
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (o instanceof StaticComponent) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static class Builder<T> {
|
public static class Builder<T> {
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue