Convert the argument validator to kotlin

This commit is contained in:
Mike Cifelli 2018-09-16 09:57:48 -04:00
parent d902328a56
commit 3f82b473b4
3 changed files with 165 additions and 235 deletions

View File

@ -10,7 +10,7 @@
<properties>
<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>
<skipTests>false</skipTests>
</properties>

View File

@ -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();
}
}
}

View File

@ -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)
}
}
}