Readded PlutoCommandParser
This commit is contained in:
parent
b476087fcd
commit
c3bd358bed
|
@ -0,0 +1,9 @@
|
|||
apply plugin: 'java-library'
|
||||
|
||||
description = ""
|
||||
|
||||
dependencies {
|
||||
api project(":plutolib")
|
||||
|
||||
testImplementation("org.junit.jupiter:junit-jupiter:5.6.2")
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package cz.tefek.pluto.command;
|
||||
|
||||
public abstract class CommandBase
|
||||
{
|
||||
public abstract String name();
|
||||
|
||||
public abstract String[] aliases();
|
||||
|
||||
public abstract String description();
|
||||
|
||||
public abstract Class<?> commandClass();
|
||||
|
||||
@Override
|
||||
public final int hashCode()
|
||||
{
|
||||
return this.name().hashCode();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
package cz.tefek.pluto.command.context;
|
||||
|
||||
import cz.tefek.pluto.command.CommandBase;
|
||||
|
||||
public class CommandContextBuilder
|
||||
{
|
||||
private CommandContext ctx;
|
||||
|
||||
public CommandContextBuilder()
|
||||
{
|
||||
this.ctx = new CommandContext();
|
||||
}
|
||||
|
||||
public CommandContextBuilder prefix(String prefix)
|
||||
{
|
||||
this.ctx.usedPrefix = prefix;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandContextBuilder alias(String alias)
|
||||
{
|
||||
this.ctx.usedAlias = alias;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandContextBuilder command(CommandBase command)
|
||||
{
|
||||
this.ctx.command = command;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public CommandContext resolved()
|
||||
{
|
||||
this.ctx.resolved = true;
|
||||
|
||||
return this.ctx;
|
||||
}
|
||||
|
||||
public CommandContext unresolved(EnumCommandParseFailure cause)
|
||||
{
|
||||
this.ctx.resolved = false;
|
||||
|
||||
return this.ctx;
|
||||
}
|
||||
|
||||
public static class CommandContext
|
||||
{
|
||||
private boolean resolved;
|
||||
private EnumCommandParseFailure failureCause;
|
||||
|
||||
private String usedPrefix;
|
||||
private String usedAlias;
|
||||
private CommandBase command;
|
||||
|
||||
private CommandContext()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public String getUsedPrefix()
|
||||
{
|
||||
return this.usedPrefix;
|
||||
}
|
||||
|
||||
public String getUsedAlias()
|
||||
{
|
||||
return this.usedAlias;
|
||||
}
|
||||
|
||||
public CommandBase getCommand()
|
||||
{
|
||||
return this.command;
|
||||
}
|
||||
|
||||
public boolean isResolved()
|
||||
{
|
||||
return this.resolved;
|
||||
}
|
||||
|
||||
public EnumCommandParseFailure getFailureCause()
|
||||
{
|
||||
return this.failureCause;
|
||||
}
|
||||
}
|
||||
|
||||
public enum EnumCommandParseFailure
|
||||
{
|
||||
UNRESOLVED_PREFIX,
|
||||
UNRESOLVED_COMMAND_NAME,
|
||||
UNRESOLVED_PARAMETERS,
|
||||
UNRESOLVED_UNEXPECTED_STATE;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,252 @@
|
|||
package cz.tefek.pluto.command.parser;
|
||||
|
||||
import java.util.PrimitiveIterator.OfInt;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import cz.tefek.pluto.command.CommandBase;
|
||||
import cz.tefek.pluto.command.context.CommandContextBuilder;
|
||||
import cz.tefek.pluto.command.context.CommandContextBuilder.CommandContext;
|
||||
import cz.tefek.pluto.command.context.CommandContextBuilder.EnumCommandParseFailure;
|
||||
import cz.tefek.pluto.command.registry.CommandRegistry;
|
||||
|
||||
public class CommandParser
|
||||
{
|
||||
private String text;
|
||||
private Set<OfInt> prefixes;
|
||||
private EnumParserState state;
|
||||
|
||||
private StringBuilder prefixBuilder;
|
||||
private StringBuilder commandNameBuilder;
|
||||
|
||||
private CommandBase command;
|
||||
|
||||
private StringBuilder parameterBuilder;
|
||||
|
||||
private CommandContextBuilder ctx;
|
||||
|
||||
private static final int CP_QUOTE = '"';
|
||||
|
||||
public CommandParser(String text)
|
||||
{
|
||||
this.text = text;
|
||||
this.state = EnumParserState.BEGIN;
|
||||
}
|
||||
|
||||
private boolean readCodepoint(int cp)
|
||||
{
|
||||
switch (this.state)
|
||||
{
|
||||
case READING_PREFIX:
|
||||
this.prefixBuilder.appendCodePoint(cp);
|
||||
|
||||
this.prefixes.removeIf(ii -> ii.nextInt() != cp);
|
||||
|
||||
if (this.prefixes.isEmpty())
|
||||
{
|
||||
this.state = EnumParserState.END_NO_PREFIX;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.hasEmptyPrefix())
|
||||
{
|
||||
this.ctx.prefix(this.prefixBuilder.toString());
|
||||
this.state = EnumParserState.READING_COMMAND;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case READING_COMMAND:
|
||||
this.commandNameBuilder.appendCodePoint(cp);
|
||||
|
||||
if (Character.isWhitespace(cp))
|
||||
{
|
||||
if (!this.resolveCommand())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
this.state = EnumParserState.READ_WHITESPACE;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case READ_WHITESPACE:
|
||||
if (Character.isWhitespace(cp))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (cp == CP_QUOTE)
|
||||
{
|
||||
this.state = EnumParserState.READING_PARAMETER_QUOTED;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.parameterBuilder.appendCodePoint(cp);
|
||||
this.state = EnumParserState.READING_PARAMETER;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case READING_PARAMETER_QUOTED:
|
||||
if (cp == CP_QUOTE)
|
||||
{
|
||||
this.state = EnumParserState.READING_PARAMETER_CANDIDATE_UNQUOTE;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.parameterBuilder.appendCodePoint(cp);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case READING_PARAMETER:
|
||||
if (Character.isWhitespace(cp))
|
||||
{
|
||||
this.emitParameter();
|
||||
this.state = EnumParserState.READ_WHITESPACE;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.parameterBuilder.appendCodePoint(cp);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case READING_PARAMETER_CANDIDATE_UNQUOTE:
|
||||
if (Character.isWhitespace(cp))
|
||||
{
|
||||
this.emitParameter();
|
||||
this.state = EnumParserState.READ_WHITESPACE;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.parameterBuilder.appendCodePoint(cp);
|
||||
this.state = EnumParserState.READING_PARAMETER_QUOTED;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case END:
|
||||
this.state = EnumParserState.UNEXPECTED_STATE_FALLBACK;
|
||||
return false;
|
||||
|
||||
default:
|
||||
this.state = EnumParserState.UNEXPECTED_STATE_FALLBACK;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean resolveCommand()
|
||||
{
|
||||
var alias = this.commandNameBuilder.toString();
|
||||
|
||||
this.ctx.alias(alias);
|
||||
|
||||
this.command = CommandRegistry.getByAlias(alias);
|
||||
|
||||
if (this.command == null)
|
||||
{
|
||||
this.state = EnumParserState.END_NO_COMMAND;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void emitParameter()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private boolean hasEmptyPrefix()
|
||||
{
|
||||
return this.prefixes.stream().anyMatch(Predicate.not(OfInt::hasNext));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse using this parser and supplied prefixes. This function also
|
||||
* resolves the command context and the parameters. Yeah it does a lot of
|
||||
* stuff.
|
||||
*
|
||||
*/
|
||||
public CommandContext parse(Set<String> prefixes)
|
||||
{
|
||||
if (this.state != EnumParserState.BEGIN)
|
||||
{
|
||||
throw new IllegalStateException("Cannot run a parser that is not in the BEGIN state.");
|
||||
}
|
||||
|
||||
this.prefixBuilder = new StringBuilder();
|
||||
this.ctx = new CommandContextBuilder();
|
||||
|
||||
this.prefixes = prefixes.stream().map(String::codePoints).map(IntStream::iterator).collect(Collectors.toSet());
|
||||
|
||||
if (prefixes.isEmpty() || this.hasEmptyPrefix())
|
||||
{
|
||||
this.state = EnumParserState.READING_COMMAND;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.state = EnumParserState.READING_PREFIX;
|
||||
}
|
||||
|
||||
this.text.codePoints().takeWhile(this::readCodepoint);
|
||||
|
||||
// Update the state for EOF
|
||||
switch (this.state)
|
||||
{
|
||||
case READING_PARAMETER_QUOTED:
|
||||
case READ_WHITESPACE:
|
||||
case READING_PARAMETER:
|
||||
case READING_PARAMETER_CANDIDATE_UNQUOTE:
|
||||
this.state = EnumParserState.END;
|
||||
this.emitParameter();
|
||||
|
||||
break;
|
||||
|
||||
case READING_COMMAND:
|
||||
if (this.resolveCommand())
|
||||
{
|
||||
this.state = EnumParserState.END;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Check the end state
|
||||
switch (this.state)
|
||||
{
|
||||
case READING_PREFIX:
|
||||
case END_NO_PREFIX:
|
||||
return this.ctx.unresolved(EnumCommandParseFailure.UNRESOLVED_PREFIX);
|
||||
|
||||
case END_NO_COMMAND:
|
||||
return this.ctx.unresolved(EnumCommandParseFailure.UNRESOLVED_COMMAND_NAME);
|
||||
|
||||
case END:
|
||||
break;
|
||||
|
||||
default:
|
||||
return this.ctx.unresolved(EnumCommandParseFailure.UNRESOLVED_UNEXPECTED_STATE);
|
||||
}
|
||||
|
||||
// At this point we are 100% sure the command was resolved and can validate the parameters
|
||||
|
||||
/*
|
||||
*
|
||||
* TODO: Validate parameters here
|
||||
*
|
||||
*/
|
||||
|
||||
return this.ctx.resolved();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package cz.tefek.pluto.command.parser;
|
||||
|
||||
public enum EnumParserState
|
||||
{
|
||||
BEGIN,
|
||||
READING_PREFIX,
|
||||
READING_COMMAND,
|
||||
READING_PARAMETER,
|
||||
READING_PARAMETER_QUOTED,
|
||||
READING_PARAMETER_CANDIDATE_UNQUOTE,
|
||||
READ_WHITESPACE,
|
||||
END_NO_PREFIX,
|
||||
END_NO_COMMAND,
|
||||
END_EMISSION_FAILURE,
|
||||
END,
|
||||
UNEXPECTED_STATE_FALLBACK;
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package cz.tefek.pluto.command.platform;
|
||||
|
||||
import cz.tefek.pluto.command.context.CommandContextBuilder.EnumCommandParseFailure;
|
||||
|
||||
public abstract class CommandPlatform
|
||||
{
|
||||
public abstract String getID();
|
||||
|
||||
public abstract String getName();
|
||||
|
||||
public boolean shouldWarnOn(EnumCommandParseFailure failure)
|
||||
{
|
||||
switch (failure)
|
||||
{
|
||||
case UNRESOLVED_PREFIX:
|
||||
case UNRESOLVED_COMMAND_NAME:
|
||||
case UNRESOLVED_UNEXPECTED_STATE:
|
||||
return false;
|
||||
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract int getMessageLimit();
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
package cz.tefek.pluto.command.registry;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import cz.tefek.pluto.command.CommandBase;
|
||||
import cz.tefek.pluto.io.logger.Logger;
|
||||
import cz.tefek.pluto.io.logger.SmartSeverity;
|
||||
|
||||
public final class CommandRegistry
|
||||
{
|
||||
private static CommandRegistry instance;
|
||||
|
||||
private final Set<CommandBase> commands;
|
||||
private final Map<String, CommandBase> aliasTable;
|
||||
|
||||
static
|
||||
{
|
||||
instance = new CommandRegistry();
|
||||
}
|
||||
|
||||
private CommandRegistry()
|
||||
{
|
||||
this.aliasTable = new HashMap<>();
|
||||
this.commands = new HashSet<>();
|
||||
}
|
||||
|
||||
private void registerAlias(String alias, CommandBase command)
|
||||
{
|
||||
if (this.aliasTable.containsKey(alias))
|
||||
{
|
||||
Logger.logf(SmartSeverity.ERROR, "Alias '%s' for command '%s' is already used, skipping.%n", alias, command.name());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.aliasTable.put(alias, command);
|
||||
}
|
||||
|
||||
public static void registerCommand(CommandBase command)
|
||||
{
|
||||
if (!instance.commands.add(command))
|
||||
{
|
||||
Logger.logf(SmartSeverity.ERROR, "Command '%s' is already registered, skipping.%n", command.name());
|
||||
return;
|
||||
}
|
||||
|
||||
instance.registerAlias(command.name(), command);
|
||||
|
||||
Arrays.stream(command.aliases()).forEach(alias -> instance.registerAlias(alias, command));
|
||||
}
|
||||
|
||||
public static CommandBase getByAlias(String alias)
|
||||
{
|
||||
return instance.aliasTable.get(alias);
|
||||
}
|
||||
|
||||
public static Set<CommandBase> getCommands()
|
||||
{
|
||||
return Collections.unmodifiableSet(instance.commands);
|
||||
}
|
||||
|
||||
public static void clear()
|
||||
{
|
||||
instance = new CommandRegistry();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package cz.tefek.pluto.command.resolver;
|
||||
|
||||
public abstract class AbstractResolveException extends RuntimeException
|
||||
{
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = -8934505669078637864L;
|
||||
|
||||
public AbstractResolveException(Exception exception)
|
||||
{
|
||||
super(exception);
|
||||
}
|
||||
|
||||
public AbstractResolveException(String what)
|
||||
{
|
||||
super(what);
|
||||
}
|
||||
|
||||
protected AbstractResolveException()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package cz.tefek.pluto.command.resolver;
|
||||
|
||||
public abstract class AbstractResolver
|
||||
{
|
||||
public abstract Class<?> getOutputType();
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package cz.tefek.pluto.command.resolver;
|
||||
|
||||
public enum EnumResolveFailure
|
||||
{
|
||||
INT_PARSE,
|
||||
LONG_PARSE,
|
||||
FLOAT_PARSE,
|
||||
DOUBLE_PARSE,
|
||||
FRAC_INVALID_PERCENTAGE,
|
||||
FRAC_PERCENTAGE_OUT_OF_RANGE,
|
||||
FRAC_VALUE_HIGHER_THAN_BASE,
|
||||
OTHER;
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package cz.tefek.pluto.command.resolver;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
public abstract class GenericResolver<R> extends AbstractResolver
|
||||
{
|
||||
protected Function<String, R> func;
|
||||
|
||||
public GenericResolver(Function<String, R> func)
|
||||
{
|
||||
this.func = func;
|
||||
}
|
||||
|
||||
public R apply(String param)
|
||||
{
|
||||
return this.func.apply(param);
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract Class<R> getOutputType();
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package cz.tefek.pluto.command.resolver;
|
||||
|
||||
public class ResolveException extends AbstractResolveException
|
||||
{
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = -3098373878754649161L;
|
||||
|
||||
private EnumResolveFailure failure;
|
||||
|
||||
public ResolveException(EnumResolveFailure failure)
|
||||
{
|
||||
this.failure = failure;
|
||||
}
|
||||
|
||||
public EnumResolveFailure getResolveFailure()
|
||||
{
|
||||
return this.failure;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package cz.tefek.pluto.command.resolver.primitive;
|
||||
|
||||
import cz.tefek.pluto.command.resolver.EnumResolveFailure;
|
||||
import cz.tefek.pluto.command.resolver.ResolveException;
|
||||
|
||||
public class BasicDoubleResolver extends DoubleResolver
|
||||
{
|
||||
public BasicDoubleResolver()
|
||||
{
|
||||
super(str ->
|
||||
{
|
||||
try
|
||||
{
|
||||
return Double.parseDouble(str);
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
throw new ResolveException(EnumResolveFailure.DOUBLE_PARSE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package cz.tefek.pluto.command.resolver.primitive;
|
||||
|
||||
import cz.tefek.pluto.command.resolver.EnumResolveFailure;
|
||||
import cz.tefek.pluto.command.resolver.ResolveException;
|
||||
|
||||
public class BasicIntResolver extends IntResolver
|
||||
{
|
||||
public BasicIntResolver()
|
||||
{
|
||||
super(str ->
|
||||
{
|
||||
try
|
||||
{
|
||||
return Integer.parseInt(str);
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
throw new ResolveException(EnumResolveFailure.INT_PARSE);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package cz.tefek.pluto.command.resolver.primitive;
|
||||
|
||||
import cz.tefek.pluto.command.resolver.EnumResolveFailure;
|
||||
import cz.tefek.pluto.command.resolver.ResolveException;
|
||||
|
||||
public class BasicLongResolver extends LongResolver
|
||||
{
|
||||
public BasicLongResolver()
|
||||
{
|
||||
super(str ->
|
||||
{
|
||||
try
|
||||
{
|
||||
return Long.parseLong(str);
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
throw new ResolveException(EnumResolveFailure.LONG_PARSE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package cz.tefek.pluto.command.resolver.primitive;
|
||||
|
||||
import java.util.function.ToDoubleFunction;
|
||||
|
||||
import cz.tefek.pluto.command.resolver.AbstractResolver;
|
||||
|
||||
public class DoubleResolver extends AbstractResolver
|
||||
{
|
||||
protected ToDoubleFunction<String> func;
|
||||
|
||||
public DoubleResolver(ToDoubleFunction<String> func)
|
||||
{
|
||||
this.func = func;
|
||||
}
|
||||
|
||||
public double apply(String param)
|
||||
{
|
||||
return this.func.applyAsDouble(param);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getOutputType()
|
||||
{
|
||||
return double.class;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
package cz.tefek.pluto.command.resolver.primitive;
|
||||
|
||||
import cz.tefek.pluto.command.resolver.EnumResolveFailure;
|
||||
import cz.tefek.pluto.command.resolver.ResolveException;
|
||||
|
||||
public class IntFractionResolver extends IntResolver
|
||||
{
|
||||
public IntFractionResolver(int base)
|
||||
{
|
||||
super(str -> parseAmount(str, base));
|
||||
}
|
||||
|
||||
private static int parseAmount(String amountString, int base) throws ResolveException
|
||||
{
|
||||
if (amountString.equalsIgnoreCase("all") || amountString.equalsIgnoreCase("everything"))
|
||||
{
|
||||
return base;
|
||||
}
|
||||
|
||||
if (amountString.equalsIgnoreCase("half"))
|
||||
{
|
||||
return base / 2;
|
||||
}
|
||||
|
||||
if (amountString.endsWith("%"))
|
||||
{
|
||||
try
|
||||
{
|
||||
float percentage = Float.parseFloat(amountString.substring(0, amountString.length() - 1));
|
||||
|
||||
if (percentage < 0 || percentage > 100)
|
||||
{
|
||||
throw new ResolveException(EnumResolveFailure.FRAC_PERCENTAGE_OUT_OF_RANGE);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Math.round(percentage / 100.0f * base);
|
||||
}
|
||||
}
|
||||
catch (NumberFormatException e1)
|
||||
{
|
||||
throw new ResolveException(EnumResolveFailure.FRAC_INVALID_PERCENTAGE);
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
int amount = Integer.parseInt(amountString);
|
||||
|
||||
if (amount > base)
|
||||
{
|
||||
throw new ResolveException(EnumResolveFailure.FRAC_VALUE_HIGHER_THAN_BASE);
|
||||
}
|
||||
|
||||
return amount;
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
throw new ResolveException(EnumResolveFailure.INT_PARSE);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package cz.tefek.pluto.command.resolver.primitive;
|
||||
|
||||
import java.util.function.ToIntFunction;
|
||||
|
||||
import cz.tefek.pluto.command.resolver.AbstractResolver;
|
||||
|
||||
public class IntResolver extends AbstractResolver
|
||||
{
|
||||
protected ToIntFunction<String> func;
|
||||
|
||||
public IntResolver(ToIntFunction<String> func)
|
||||
{
|
||||
this.func = func;
|
||||
}
|
||||
|
||||
public int apply(String param)
|
||||
{
|
||||
return this.func.applyAsInt(param);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Class<?> getOutputType()
|
||||
{
|
||||
return int.class;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package cz.tefek.pluto.command.resolver.primitive;
|
||||
|
||||
import java.util.function.ToLongFunction;
|
||||
|
||||
import cz.tefek.pluto.command.resolver.AbstractResolver;
|
||||
|
||||
public class LongResolver extends AbstractResolver
|
||||
{
|
||||
protected ToLongFunction<String> func;
|
||||
|
||||
public LongResolver(ToLongFunction<String> func)
|
||||
{
|
||||
this.func = func;
|
||||
}
|
||||
|
||||
public long apply(String param)
|
||||
{
|
||||
return this.func.applyAsLong(param);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Class<?> getOutputType()
|
||||
{
|
||||
return long.class;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package cz.tefek.pluto.command.resolver;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import cz.tefek.pluto.command.resolver.primitive.BasicIntResolver;
|
||||
|
||||
class BasicIntResolverTest
|
||||
{
|
||||
@Test
|
||||
void parse()
|
||||
{
|
||||
var resolver = new BasicIntResolver();
|
||||
|
||||
Assertions.assertEquals(5, resolver.apply("5"));
|
||||
|
||||
Assertions.assertEquals(-50, resolver.apply("-50"));
|
||||
|
||||
Assertions.assertEquals(155, resolver.apply("155"));
|
||||
|
||||
Assertions.assertEquals(0, resolver.apply("0"));
|
||||
|
||||
Assertions.assertEquals(-0, resolver.apply("-0"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void exceptions()
|
||||
{
|
||||
var resolver = new BasicIntResolver();
|
||||
|
||||
// No foreign characters
|
||||
Assertions.assertThrows(NumberFormatException.class, () -> resolver.apply("abc"));
|
||||
|
||||
// No floats
|
||||
Assertions.assertThrows(NumberFormatException.class, () -> resolver.apply("12.5"));
|
||||
|
||||
// No empty strings
|
||||
Assertions.assertThrows(NumberFormatException.class, () -> resolver.apply(""));
|
||||
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
include 'plutolib',
|
||||
'plutocommandparser',
|
||||
'plutostatic',
|
||||
'plutotexturing',
|
||||
'plutomesher',
|
||||
|
|
Loading…
Reference in New Issue