Convert the argument validator to kotlin
This commit is contained in:
parent
d902328a56
commit
3f82b473b4
2
pom.xml
2
pom.xml
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<kotlin.version>1.2.60</kotlin.version>
|
<kotlin.version>1.2.70</kotlin.version>
|
||||||
<junit5.version>5.2.0</junit5.version>
|
<junit5.version>5.2.0</junit5.version>
|
||||||
<skipTests>false</skipTests>
|
<skipTests>false</skipTests>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
|
@ -1,234 +0,0 @@
|
||||||
package function;
|
|
||||||
|
|
||||||
import error.LispException;
|
|
||||||
import sexpression.Cons;
|
|
||||||
import sexpression.DisplayName;
|
|
||||||
import sexpression.SExpression;
|
|
||||||
|
|
||||||
import java.math.BigInteger;
|
|
||||||
|
|
||||||
import static function.builtin.cons.LENGTH.getLength;
|
|
||||||
import static java.text.MessageFormat.format;
|
|
||||||
|
|
||||||
public class ArgumentValidator {
|
|
||||||
|
|
||||||
private Class<? extends SExpression> firstArgumentType;
|
|
||||||
private Class<? extends SExpression> trailingArgumentType;
|
|
||||||
private Class<? extends SExpression> excludedFirstArgumentType;
|
|
||||||
private Class<? extends SExpression> excludedTrailingArgumentType;
|
|
||||||
private String functionName;
|
|
||||||
private BigInteger maximumNumberOfArguments;
|
|
||||||
private BigInteger minimumNumberOfArguments;
|
|
||||||
|
|
||||||
public ArgumentValidator(String functionName) {
|
|
||||||
this.firstArgumentType = SExpression.class;
|
|
||||||
this.trailingArgumentType = SExpression.class;
|
|
||||||
this.excludedFirstArgumentType = null;
|
|
||||||
this.excludedTrailingArgumentType = null;
|
|
||||||
this.functionName = functionName;
|
|
||||||
this.minimumNumberOfArguments = null;
|
|
||||||
this.maximumNumberOfArguments = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setFirstArgumentExpectedType(Class<? extends SExpression> argumentType) {
|
|
||||||
this.firstArgumentType = argumentType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTrailingArgumentExpectedType(Class<? extends SExpression> argumentType) {
|
|
||||||
this.trailingArgumentType = argumentType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEveryArgumentExpectedType(Class<? extends SExpression> argumentType) {
|
|
||||||
this.firstArgumentType = argumentType;
|
|
||||||
this.trailingArgumentType = argumentType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setFirstArgumentExcludedType(Class<? extends SExpression> argumentType) {
|
|
||||||
this.excludedFirstArgumentType = argumentType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTrailingArgumentExcludedType(Class<? extends SExpression> argumentType) {
|
|
||||||
this.excludedTrailingArgumentType = argumentType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEveryArgumentExcludedType(Class<? extends SExpression> argumentType) {
|
|
||||||
this.excludedFirstArgumentType = argumentType;
|
|
||||||
this.excludedTrailingArgumentType = argumentType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMaximumNumberOfArguments(int maximumNumberOfArguments) {
|
|
||||||
this.maximumNumberOfArguments = BigInteger.valueOf(maximumNumberOfArguments);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMinimumNumberOfArguments(int minimumNumberOfArguments) {
|
|
||||||
this.minimumNumberOfArguments = BigInteger.valueOf(minimumNumberOfArguments);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setExactNumberOfArguments(int exactNumberOfArguments) {
|
|
||||||
this.minimumNumberOfArguments = BigInteger.valueOf(exactNumberOfArguments);
|
|
||||||
this.maximumNumberOfArguments = BigInteger.valueOf(exactNumberOfArguments);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void validate(Cons argumentList) {
|
|
||||||
validateListNotDotted(argumentList);
|
|
||||||
validateListLength(argumentList);
|
|
||||||
validateArgumentTypes(argumentList);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void validateListNotDotted(Cons argumentList) {
|
|
||||||
SExpression next = argumentList.getRest();
|
|
||||||
|
|
||||||
for (Cons current = argumentList; next.isCons(); next = current.getRest())
|
|
||||||
current = (Cons) next;
|
|
||||||
|
|
||||||
if (!next.isNull())
|
|
||||||
throw new DottedArgumentListException(functionName, argumentList);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void validateListLength(Cons argumentList) {
|
|
||||||
if (containsTooFewArguments(argumentList))
|
|
||||||
throw new TooFewArgumentsException(functionName, argumentList);
|
|
||||||
else if (containsTooManyArguments(argumentList))
|
|
||||||
throw new TooManyArgumentsException(functionName, argumentList);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean containsTooFewArguments(Cons argumentList) {
|
|
||||||
return isMinimum() && isLengthLessThanMinimum(argumentList);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isMinimum() {
|
|
||||||
return minimumNumberOfArguments != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isLengthLessThanMinimum(Cons argumentList) {
|
|
||||||
return getLength(argumentList).compareTo(minimumNumberOfArguments) < 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean containsTooManyArguments(Cons argumentList) {
|
|
||||||
return isMaximum() && isLengthGreaterThanMaximum(argumentList);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isMaximum() {
|
|
||||||
return maximumNumberOfArguments != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isLengthGreaterThanMaximum(Cons argumentList) {
|
|
||||||
return getLength(argumentList).compareTo(maximumNumberOfArguments) > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void validateArgumentTypes(Cons argumentList) {
|
|
||||||
validateFirstArgument(argumentList);
|
|
||||||
validateTrailingArguments(argumentList);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void validateFirstArgument(Cons argumentList) {
|
|
||||||
if (!isFirstArgumentValid(argumentList))
|
|
||||||
throw new BadArgumentTypeException(functionName, argumentList.getFirst(), firstArgumentType);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isFirstArgumentValid(Cons argumentList) {
|
|
||||||
return argumentList.isNull() || isExpectedFirstArgumentType(argumentList.getFirst());
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isExpectedFirstArgumentType(SExpression firstArgument) {
|
|
||||||
return firstArgumentType.isInstance(firstArgument) && !isExcludedFirstArgumentType(firstArgument);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isExcludedFirstArgumentType(SExpression firstArgument) {
|
|
||||||
return excludedFirstArgumentType != null && excludedFirstArgumentType.isInstance(firstArgument);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void validateTrailingArguments(Cons argumentList) {
|
|
||||||
for (Cons cons = (Cons) argumentList.getRest(); !cons.isNull(); cons = (Cons) cons.getRest())
|
|
||||||
if (!isExpectedTrailingArgumentType(cons.getFirst()))
|
|
||||||
throw new BadArgumentTypeException(functionName, cons.getFirst(), trailingArgumentType);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isExpectedTrailingArgumentType(SExpression trailingArgument) {
|
|
||||||
return trailingArgumentType.isInstance(trailingArgument) && !isExcludedTrailingArgumentType(trailingArgument);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isExcludedTrailingArgumentType(SExpression trailingArgument) {
|
|
||||||
return excludedTrailingArgumentType != null && excludedTrailingArgumentType.isInstance(trailingArgument);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class TooFewArgumentsException extends LispException {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
private String functionName;
|
|
||||||
private Cons argumentList;
|
|
||||||
|
|
||||||
public TooFewArgumentsException(String functionName, Cons argumentList) {
|
|
||||||
this.functionName = functionName;
|
|
||||||
this.argumentList = argumentList;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getMessage() {
|
|
||||||
return format("too few arguments given to {0}: {1}", functionName, argumentList);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class TooManyArgumentsException extends LispException {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
private String functionName;
|
|
||||||
private Cons argumentList;
|
|
||||||
|
|
||||||
public TooManyArgumentsException(String functionName, Cons argumentList) {
|
|
||||||
this.functionName = functionName;
|
|
||||||
this.argumentList = argumentList;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getMessage() {
|
|
||||||
return format("too many arguments given to {0}: {1}", functionName, argumentList);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class DottedArgumentListException extends LispException {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
private String functionName;
|
|
||||||
private Cons argumentList;
|
|
||||||
|
|
||||||
public DottedArgumentListException(String functionName, Cons argumentList) {
|
|
||||||
this.functionName = functionName;
|
|
||||||
this.argumentList = argumentList;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getMessage() {
|
|
||||||
return format("dotted argument list given to {0}: {1}", functionName, argumentList);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class BadArgumentTypeException extends LispException {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
private String functionName;
|
|
||||||
private String argument;
|
|
||||||
private Class<? extends SExpression> expectedType;
|
|
||||||
|
|
||||||
public BadArgumentTypeException(String functionName, SExpression argument,
|
|
||||||
Class<? extends SExpression> expectedType) {
|
|
||||||
this.functionName = functionName;
|
|
||||||
this.argument = argument.toString();
|
|
||||||
this.expectedType = expectedType;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getMessage() {
|
|
||||||
return format("{0}: {1} is not the expected type of ''{2}''",
|
|
||||||
functionName,
|
|
||||||
argument,
|
|
||||||
getExpectedTypeName());
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getExpectedTypeName() {
|
|
||||||
DisplayName displayName = expectedType.getAnnotation(DisplayName.class);
|
|
||||||
|
|
||||||
return (displayName == null) ? "unknown" : displayName.value();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,164 @@
|
||||||
|
package function
|
||||||
|
|
||||||
|
import error.LispException
|
||||||
|
import function.builtin.cons.LENGTH.getLength
|
||||||
|
import sexpression.Cons
|
||||||
|
import sexpression.DisplayName
|
||||||
|
import sexpression.SExpression
|
||||||
|
import java.math.BigInteger
|
||||||
|
import java.text.MessageFormat.format
|
||||||
|
|
||||||
|
class ArgumentValidator(private val functionName: String) {
|
||||||
|
|
||||||
|
private var firstArgumentType: Class<out SExpression> = SExpression::class.java
|
||||||
|
private var trailingArgumentType: Class<out SExpression> = SExpression::class.java
|
||||||
|
private var excludedFirstArgumentType: Class<out SExpression>? = null
|
||||||
|
private var excludedTrailingArgumentType: Class<out SExpression>? = null
|
||||||
|
private var maximumNumberOfArguments: BigInteger? = null
|
||||||
|
private var minimumNumberOfArguments: BigInteger? = null
|
||||||
|
|
||||||
|
fun setFirstArgumentExpectedType(argumentType: Class<out SExpression>) {
|
||||||
|
this.firstArgumentType = argumentType
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setTrailingArgumentExpectedType(argumentType: Class<out SExpression>) {
|
||||||
|
this.trailingArgumentType = argumentType
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setEveryArgumentExpectedType(argumentType: Class<out SExpression>) {
|
||||||
|
this.firstArgumentType = argumentType
|
||||||
|
this.trailingArgumentType = argumentType
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setFirstArgumentExcludedType(argumentType: Class<out SExpression>) {
|
||||||
|
this.excludedFirstArgumentType = argumentType
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setTrailingArgumentExcludedType(argumentType: Class<out SExpression>) {
|
||||||
|
this.excludedTrailingArgumentType = argumentType
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setEveryArgumentExcludedType(argumentType: Class<out SExpression>) {
|
||||||
|
this.excludedFirstArgumentType = argumentType
|
||||||
|
this.excludedTrailingArgumentType = argumentType
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setMaximumNumberOfArguments(maximumNumberOfArguments: Int) {
|
||||||
|
this.maximumNumberOfArguments = BigInteger.valueOf(maximumNumberOfArguments.toLong())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setMinimumNumberOfArguments(minimumNumberOfArguments: Int) {
|
||||||
|
this.minimumNumberOfArguments = BigInteger.valueOf(minimumNumberOfArguments.toLong())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setExactNumberOfArguments(exactNumberOfArguments: Int) {
|
||||||
|
this.minimumNumberOfArguments = BigInteger.valueOf(exactNumberOfArguments.toLong())
|
||||||
|
this.maximumNumberOfArguments = BigInteger.valueOf(exactNumberOfArguments.toLong())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun validate(argumentList: Cons) {
|
||||||
|
validateListNotDotted(argumentList)
|
||||||
|
validateListLength(argumentList)
|
||||||
|
validateArgumentTypes(argumentList)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun validateListNotDotted(argumentList: Cons) {
|
||||||
|
var current = argumentList
|
||||||
|
var next = current.rest
|
||||||
|
|
||||||
|
while (next.isCons) {
|
||||||
|
current = next as Cons
|
||||||
|
next = current.rest
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!next.isNull)
|
||||||
|
throw DottedArgumentListException(functionName, argumentList)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun validateListLength(argumentList: Cons) {
|
||||||
|
if (containsTooFewArguments(argumentList))
|
||||||
|
throw TooFewArgumentsException(functionName, argumentList)
|
||||||
|
else if (containsTooManyArguments(argumentList))
|
||||||
|
throw TooManyArgumentsException(functionName, argumentList)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun containsTooFewArguments(argumentList: Cons) = isMinimum() && isLengthLessThanMinimum(argumentList)
|
||||||
|
private fun isMinimum() = minimumNumberOfArguments != null
|
||||||
|
private fun isLengthLessThanMinimum(argumentList: Cons) = getLength(argumentList) < minimumNumberOfArguments!!
|
||||||
|
|
||||||
|
private fun containsTooManyArguments(argumentList: Cons) = isMaximum() && isLengthGreaterThanMaximum(argumentList)
|
||||||
|
private fun isMaximum() = maximumNumberOfArguments != null
|
||||||
|
private fun isLengthGreaterThanMaximum(argumentList: Cons) = getLength(argumentList) > maximumNumberOfArguments!!
|
||||||
|
|
||||||
|
private fun validateArgumentTypes(argumentList: Cons) {
|
||||||
|
validateFirstArgument(argumentList)
|
||||||
|
validateTrailingArguments(argumentList)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun validateFirstArgument(argumentList: Cons) {
|
||||||
|
if (!isFirstArgumentValid(argumentList))
|
||||||
|
throw BadArgumentTypeException(functionName, argumentList.first, firstArgumentType)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isFirstArgumentValid(argumentList: Cons) =
|
||||||
|
argumentList.isNull || isExpectedFirstArgumentType(argumentList.first)
|
||||||
|
|
||||||
|
private fun isExpectedFirstArgumentType(firstArgument: SExpression) =
|
||||||
|
firstArgumentType.isInstance(firstArgument) && !isExcludedFirstArgumentType(firstArgument)
|
||||||
|
|
||||||
|
private fun isExcludedFirstArgumentType(firstArgument: SExpression) =
|
||||||
|
excludedFirstArgumentType != null && excludedFirstArgumentType!!.isInstance(firstArgument)
|
||||||
|
|
||||||
|
private fun validateTrailingArguments(argumentList: Cons) {
|
||||||
|
var cons = argumentList.rest as Cons
|
||||||
|
|
||||||
|
while (!cons.isNull) {
|
||||||
|
if (!isExpectedTrailingArgumentType(cons.first))
|
||||||
|
throw BadArgumentTypeException(functionName, cons.first, trailingArgumentType)
|
||||||
|
|
||||||
|
cons = cons.rest as Cons
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isExpectedTrailingArgumentType(trailingArgument: SExpression) =
|
||||||
|
trailingArgumentType.isInstance(trailingArgument) && !isExcludedTrailingArgumentType(trailingArgument)
|
||||||
|
|
||||||
|
private fun isExcludedTrailingArgumentType(trailingArgument: SExpression) =
|
||||||
|
excludedTrailingArgumentType != null && excludedTrailingArgumentType!!.isInstance(trailingArgument)
|
||||||
|
|
||||||
|
class TooFewArgumentsException(functionName: String, argumentList: Cons) : LispException() {
|
||||||
|
|
||||||
|
override val message: String by lazy {
|
||||||
|
format("too few arguments given to {0}: {1}", functionName, argumentList)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TooManyArgumentsException(functionName: String, argumentList: Cons) : LispException() {
|
||||||
|
|
||||||
|
override val message: String by lazy {
|
||||||
|
format("too many arguments given to {0}: {1}", functionName, argumentList)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DottedArgumentListException(functionName: String, argumentList: Cons) : LispException() {
|
||||||
|
|
||||||
|
override val message: String by lazy {
|
||||||
|
format("dotted argument list given to {0}: {1}", functionName, argumentList)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BadArgumentTypeException(functionName: String,
|
||||||
|
argument: SExpression,
|
||||||
|
expectedType: Class<out SExpression>?) : LispException() {
|
||||||
|
|
||||||
|
private val expectedTypeName: String by lazy {
|
||||||
|
val displayName = expectedType?.getAnnotation(DisplayName::class.java)
|
||||||
|
|
||||||
|
displayName?.value ?: "unknown"
|
||||||
|
}
|
||||||
|
|
||||||
|
override val message: String by lazy {
|
||||||
|
format("{0}: {1} is not the expected type of ''{2}''", functionName, argument.toString(), expectedTypeName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue