diff --git a/pom.xml b/pom.xml
index bd817f6..685e2d2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -10,7 +10,7 @@
UTF-8
- 1.2.60
+ 1.2.70
5.2.0
false
diff --git a/src/main/kotlin/function/ArgumentValidator.java b/src/main/kotlin/function/ArgumentValidator.java
deleted file mode 100644
index dc0db05..0000000
--- a/src/main/kotlin/function/ArgumentValidator.java
+++ /dev/null
@@ -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();
- }
- }
-}
diff --git a/src/main/kotlin/function/ArgumentValidator.kt b/src/main/kotlin/function/ArgumentValidator.kt
new file mode 100644
index 0000000..c22dcce
--- /dev/null
+++ b/src/main/kotlin/function/ArgumentValidator.kt
@@ -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 = SExpression::class.java
+ private var trailingArgumentType: Class = SExpression::class.java
+ private var excludedFirstArgumentType: Class? = null
+ private var excludedTrailingArgumentType: Class? = null
+ private var maximumNumberOfArguments: BigInteger? = null
+ private var minimumNumberOfArguments: BigInteger? = null
+
+ fun setFirstArgumentExpectedType(argumentType: Class) {
+ this.firstArgumentType = argumentType
+ }
+
+ fun setTrailingArgumentExpectedType(argumentType: Class) {
+ this.trailingArgumentType = argumentType
+ }
+
+ fun setEveryArgumentExpectedType(argumentType: Class) {
+ this.firstArgumentType = argumentType
+ this.trailingArgumentType = argumentType
+ }
+
+ fun setFirstArgumentExcludedType(argumentType: Class) {
+ this.excludedFirstArgumentType = argumentType
+ }
+
+ fun setTrailingArgumentExcludedType(argumentType: Class) {
+ this.excludedTrailingArgumentType = argumentType
+ }
+
+ fun setEveryArgumentExcludedType(argumentType: Class) {
+ 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?) : 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)
+ }
+ }
+}