Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for return values other than ints with backwards-compatability #123

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,7 @@ gradle-app.setting
hs_err_pid*


repo/
repo/

# vscode workspace settings
.vscode
4 changes: 2 additions & 2 deletions src/main/java/com/mojang/brigadier/Command.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
import com.mojang.brigadier.exceptions.CommandSyntaxException;

@FunctionalInterface
public interface Command<S> {
public interface Command<S, R> {
int SINGLE_SUCCESS = 1;

int run(CommandContext<S> context) throws CommandSyntaxException;
R run(CommandContext<S> context) throws CommandSyntaxException;
}
27 changes: 15 additions & 12 deletions src/main/java/com/mojang/brigadier/CommandDispatcher.java
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation and Serena Lynas. All rights reserved.
// Licensed under the MIT license.

package com.mojang.brigadier;
Expand All @@ -8,6 +8,9 @@
import com.mojang.brigadier.context.CommandContextBuilder;
import com.mojang.brigadier.context.SuggestionContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.results.CommandResult;
import com.mojang.brigadier.results.EmptyCommandResult;
import com.mojang.brigadier.results.ListCommandResult;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import com.mojang.brigadier.tree.CommandNode;
Expand Down Expand Up @@ -62,7 +65,7 @@ public boolean test(final CommandNode<S> input) {
return input != null && (input.getCommand() != null || input.getChildren().stream().anyMatch(hasCommand));
}
};
private ResultConsumer<S> consumer = (c, s, r) -> {
private ResultConsumer<S, Object> consumer = (c, s, r) -> {
};

/**
Expand Down Expand Up @@ -104,7 +107,7 @@ public LiteralCommandNode<S> register(final LiteralArgumentBuilder<S> command) {
*
* @param consumer the new result consumer to be called
*/
public void setConsumer(final ResultConsumer<S> consumer) {
public void setConsumer(final ResultConsumer<S, Object> consumer) {
this.consumer = consumer;
}

Expand Down Expand Up @@ -138,7 +141,7 @@ public void setConsumer(final ResultConsumer<S> consumer) {
* @see #execute(ParseResults)
* @see #execute(StringReader, Object)
*/
public int execute(final String input, final S source) throws CommandSyntaxException {
public Object execute(final String input, final S source) throws CommandSyntaxException {
return execute(new StringReader(input), source);
}

Expand Down Expand Up @@ -172,7 +175,7 @@ public int execute(final String input, final S source) throws CommandSyntaxExcep
* @see #execute(ParseResults)
* @see #execute(String, Object)
*/
public int execute(final StringReader input, final S source) throws CommandSyntaxException {
public Object execute(final StringReader input, final S source) throws CommandSyntaxException {
final ParseResults<S> parse = parse(input, source);
return execute(parse);
}
Expand Down Expand Up @@ -203,7 +206,7 @@ public int execute(final StringReader input, final S source) throws CommandSynta
* @see #execute(String, Object)
* @see #execute(StringReader, Object)
*/
public int execute(final ParseResults<S> parse) throws CommandSyntaxException {
public Object execute(final ParseResults<S> parse) throws CommandSyntaxException {
if (parse.getReader().canRead()) {
if (parse.getExceptions().size() == 1) {
throw parse.getExceptions().values().iterator().next();
Expand All @@ -214,7 +217,7 @@ public int execute(final ParseResults<S> parse) throws CommandSyntaxException {
}
}

int result = 0;
Object result = new EmptyCommandResult();
int successfulForks = 0;
boolean forked = false;
boolean foundCommand = false;
Expand Down Expand Up @@ -250,7 +253,7 @@ public int execute(final ParseResults<S> parse) throws CommandSyntaxException {
}
}
} catch (final CommandSyntaxException ex) {
consumer.onCommandComplete(context, false, 0);
consumer.onCommandComplete(context, false, new EmptyCommandResult());
if (!forked) {
throw ex;
}
Expand All @@ -260,12 +263,12 @@ public int execute(final ParseResults<S> parse) throws CommandSyntaxException {
} else if (context.getCommand() != null) {
foundCommand = true;
try {
final int value = context.getCommand().run(context);
result += value;
final Object value = context.getCommand().run(context);
consumer.onCommandComplete(context, true, value);
result = CommandResult.combine(result, value);
successfulForks++;
} catch (final CommandSyntaxException ex) {
consumer.onCommandComplete(context, false, 0);
consumer.onCommandComplete(context, false, new EmptyCommandResult());
if (!forked) {
throw ex;
}
Expand All @@ -278,7 +281,7 @@ public int execute(final ParseResults<S> parse) throws CommandSyntaxException {
}

if (!foundCommand) {
consumer.onCommandComplete(original, false, 0);
consumer.onCommandComplete(original, false, new EmptyCommandResult());
throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownCommand().createWithContext(parse.getReader());
}

Expand Down
4 changes: 2 additions & 2 deletions src/main/java/com/mojang/brigadier/ResultConsumer.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@
import com.mojang.brigadier.context.CommandContext;

@FunctionalInterface
public interface ResultConsumer<S> {
void onCommandComplete(CommandContext<S> context, boolean success, int result);
public interface ResultConsumer<S, R> {
void onCommandComplete(CommandContext<S> context, boolean success, R result);
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

public abstract class ArgumentBuilder<S, T extends ArgumentBuilder<S, T>> {
private final RootCommandNode<S> arguments = new RootCommandNode<>();
private Command<S> command;
private Command<S, ?> command;
private Predicate<S> requirement = s -> true;
private CommandNode<S> target;
private RedirectModifier<S> modifier = null;
Expand Down Expand Up @@ -43,12 +43,12 @@ public Collection<CommandNode<S>> getArguments() {
return arguments.getChildren();
}

public T executes(final Command<S> command) {
public <R> T executes(final Command<S, R> command) {
this.command = command;
return getThis();
}

public Command<S> getCommand() {
public Command<S, ?> getCommand() {
return command;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public class CommandContext<S> {

private final S source;
private final String input;
private final Command<S> command;
private final Command<S, ?> command;
private final Map<String, ParsedArgument<S, ?>> arguments;
private final CommandNode<S> rootNode;
private final List<ParsedCommandNode<S>> nodes;
Expand All @@ -37,7 +37,7 @@ public class CommandContext<S> {
private final RedirectModifier<S> modifier;
private final boolean forks;

public CommandContext(final S source, final String input, final Map<String, ParsedArgument<S, ?>> arguments, final Command<S> command, final CommandNode<S> rootNode, final List<ParsedCommandNode<S>> nodes, final StringRange range, final CommandContext<S> child, final RedirectModifier<S> modifier, boolean forks) {
public CommandContext(final S source, final String input, final Map<String, ParsedArgument<S, ?>> arguments, final Command<S, ?> command, final CommandNode<S> rootNode, final List<ParsedCommandNode<S>> nodes, final StringRange range, final CommandContext<S> child, final RedirectModifier<S> modifier, boolean forks) {
this.source = source;
this.input = input;
this.arguments = arguments;
Expand Down Expand Up @@ -69,7 +69,7 @@ public CommandContext<S> getLastChild() {
return result;
}

public Command<S> getCommand() {
public Command<S, ?> getCommand() {
return command;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public class CommandContextBuilder<S> {
private final List<ParsedCommandNode<S>> nodes = new ArrayList<>();
private final CommandDispatcher<S> dispatcher;
private S source;
private Command<S> command;
private Command<S, ?> command;
private CommandContextBuilder<S> child;
private StringRange range;
private RedirectModifier<S> modifier = null;
Expand Down Expand Up @@ -54,7 +54,7 @@ public CommandContextBuilder<S> withArgument(final String name, final ParsedArgu
return arguments;
}

public CommandContextBuilder<S> withCommand(final Command<S> command) {
public CommandContextBuilder<S> withCommand(final Command<S, ?> command) {
this.command = command;
return this;
}
Expand Down Expand Up @@ -95,7 +95,7 @@ public CommandContextBuilder<S> getLastChild() {
return result;
}

public Command<S> getCommand() {
public Command<S, ?> getCommand() {
return command;
}

Expand Down
39 changes: 39 additions & 0 deletions src/main/java/com/mojang/brigadier/results/CommandResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright (c) Serena Lynas. All rights reserved.
// Licensed under the MIT license.

package com.mojang.brigadier.results;

/**
* Optional interface for CommandResult
*
* Not all things returned from commands
* must implement this interface.
*/
public interface CommandResult {
/**
* Combine one command result with another, returning
* the combined result.
* @param other The other result to combine this result
* with.
* @return The combined result
*/
default Object combine(Object other) {
ListCommandResult list = new ListCommandResult();
list.combine(this);
list.combine(other);
return list;
}

static Object combine(Object target, Object source) {
if (target instanceof CommandResult) {
return ((CommandResult)target).combine(source);
} else if (target instanceof Integer && source instanceof Integer) {
// Backwards compatability
return (Integer)target + (Integer)source;
} else if (source instanceof EmptyCommandResult) {
return target;
} else {
return source;
}
}
}
19 changes: 19 additions & 0 deletions src/main/java/com/mojang/brigadier/results/EmptyCommandResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright (c) Serena Lynas. All rights reserved.
// Licensed under the MIT license.

package com.mojang.brigadier.results;

/**
* Empty class which semantically represents
* an empty command result.
*/
public class EmptyCommandResult implements CommandResult {
/**
* Combines this result with another. Always overwrites
* the empty result.
*/
@Override
public Object combine(Object other) {
return other;
}
}
24 changes: 24 additions & 0 deletions src/main/java/com/mojang/brigadier/results/ListCommandResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright (c) Serena Lynas. All rights reserved.
// Licensed under the MIT license.

package com.mojang.brigadier.results;

import java.util.ArrayList;
import java.util.List;

public class ListCommandResult implements CommandResult {
private List<Object> results = new ArrayList<>();

public List<Object> getResults() {
return results;
}

@Override
public ListCommandResult combine(Object other) {
if (!(other instanceof EmptyCommandResult)) {
results.add(other);
}

return this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public class ArgumentCommandNode<S, T> extends CommandNode<S> {
private final ArgumentType<T> type;
private final SuggestionProvider<S> customSuggestions;

public ArgumentCommandNode(final String name, final ArgumentType<T> type, final Command<S> command, final Predicate<S> requirement, final CommandNode<S> redirect, final RedirectModifier<S> modifier, final boolean forks, final SuggestionProvider<S> customSuggestions) {
public ArgumentCommandNode(final String name, final ArgumentType<T> type, final Command<S, ?> command, final Predicate<S> requirement, final CommandNode<S> redirect, final RedirectModifier<S> modifier, final boolean forks, final SuggestionProvider<S> customSuggestions) {
super(command, requirement, redirect, modifier, forks);
this.name = name;
this.type = type;
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/com/mojang/brigadier/tree/CommandNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,17 @@ public abstract class CommandNode<S> implements Comparable<CommandNode<S>> {
private final CommandNode<S> redirect;
private final RedirectModifier<S> modifier;
private final boolean forks;
private Command<S> command;
private Command<S, ?> command;

protected CommandNode(final Command<S> command, final Predicate<S> requirement, final CommandNode<S> redirect, final RedirectModifier<S> modifier, final boolean forks) {
protected CommandNode(final Command<S, ?> command, final Predicate<S> requirement, final CommandNode<S> redirect, final RedirectModifier<S> modifier, final boolean forks) {
this.command = command;
this.requirement = requirement;
this.redirect = redirect;
this.modifier = modifier;
this.forks = forks;
}

public Command<S> getCommand() {
public Command<S, ?> getCommand() {
return command;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public class LiteralCommandNode<S> extends CommandNode<S> {
private final String literal;
private final String literalLowerCase;

public LiteralCommandNode(final String literal, final Command<S> command, final Predicate<S> requirement, final CommandNode<S> redirect, final RedirectModifier<S> modifier, final boolean forks) {
public LiteralCommandNode(final String literal, final Command<S, ?> command, final Predicate<S> requirement, final CommandNode<S> redirect, final RedirectModifier<S> modifier, final boolean forks) {
super(command, requirement, redirect, modifier, forks);
this.literal = literal;
this.literalLowerCase = literal.toLowerCase(Locale.ROOT);
Expand Down
10 changes: 5 additions & 5 deletions src/test/java/com/mojang/brigadier/CommandDispatcherTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
public class CommandDispatcherTest {
private CommandDispatcher<Object> subject;
@Mock
private Command<Object> command;
private Command<Object, Integer> command;
@Mock
private Object source;

Expand Down Expand Up @@ -167,7 +167,7 @@ public void testExecuteAmbiguousIncorrectArgument() throws Exception {
@SuppressWarnings("unchecked")
@Test
public void testExecuteSubcommand() throws Exception {
final Command<Object> subCommand = mock(Command.class);
final Command<Object, Integer> subCommand = mock(Command.class);
when(subCommand.run(any())).thenReturn(100);

subject.register(literal("foo").then(
Expand Down Expand Up @@ -205,7 +205,7 @@ public void testParseIncompleteArgument() throws Exception {
@SuppressWarnings("unchecked")
@Test
public void testExecuteAmbiguiousParentSubcommand() throws Exception {
final Command<Object> subCommand = mock(Command.class);
final Command<Object, Integer> subCommand = mock(Command.class);
when(subCommand.run(any())).thenReturn(100);

subject.register(
Expand All @@ -231,7 +231,7 @@ public void testExecuteAmbiguiousParentSubcommand() throws Exception {
@SuppressWarnings("unchecked")
@Test
public void testExecuteAmbiguiousParentSubcommandViaRedirect() throws Exception {
final Command<Object> subCommand = mock(Command.class);
final Command<Object, Integer> subCommand = mock(Command.class);
when(subCommand.run(any())).thenReturn(100);

final LiteralCommandNode<Object> real = subject.register(
Expand Down Expand Up @@ -343,7 +343,7 @@ public void testExecuteOrphanedSubcommand() throws Exception {

@Test
public void testExecute_invalidOther() throws Exception {
final Command<Object> wrongCommand = mock(Command.class);
final Command<Object, Integer> wrongCommand = mock(Command.class);
subject.register(literal("w").executes(wrongCommand));
subject.register(literal("world").executes(command));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public class CommandDispatcherUsagesTest {
@Mock
private Object source;
@Mock
private Command<Object> command;
private Command<Object, Integer> command;

@Before
public void setUp() throws Exception {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public class LiteralArgumentBuilderTest {
private LiteralArgumentBuilder<Object> builder;
@Mock
private
Command<Object> command;
Command<Object, Integer> command;

@Before
public void setUp() throws Exception {
Expand Down
Loading