diff --git a/src/function/ArgumentValidator.java b/src/function/ArgumentValidator.java index a79f1b3..96a1a78 100644 --- a/src/function/ArgumentValidator.java +++ b/src/function/ArgumentValidator.java @@ -12,18 +12,20 @@ public class ArgumentValidator { private Class firstArgumentType; private Class trailingArgumentType; + private Class excludedFirstArgumentType; + private Class excludedTrailingArgumentType; private String functionName; private BigInteger maximumNumberOfArguments; private BigInteger minimumNumberOfArguments; - private boolean isNilAcceptable; 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; - this.isNilAcceptable = true; } public void setFirstArgumentExpectedType(Class argumentType) { @@ -38,6 +40,19 @@ public class ArgumentValidator { this.firstArgumentType = argumentType; this.trailingArgumentType = argumentType; } + + public void setFirstArgumentExcludedType(Class argumentType) { + this.excludedFirstArgumentType = argumentType; + } + + public void setTrailingArgumentExcludedType(Class argumentType) { + this.excludedTrailingArgumentType = argumentType; + } + + public void setEveryArgumentExcludedType(Class argumentType) { + this.excludedFirstArgumentType = argumentType; + this.excludedTrailingArgumentType = argumentType; + } public void setMaximumNumberOfArguments(int maximumNumberOfArguments) { this.maximumNumberOfArguments = BigInteger.valueOf(maximumNumberOfArguments); @@ -52,10 +67,6 @@ public class ArgumentValidator { this.maximumNumberOfArguments = BigInteger.valueOf(exactNumberOfArguments); } - public void doNotAcceptNil() { - this.isNilAcceptable = false; - } - public void validate(Cons argumentList) { validateListNotDotted(argumentList); validateListLength(argumentList); @@ -118,11 +129,11 @@ public class ArgumentValidator { } private boolean isExpectedFirstArgumentType(SExpression firstArgument) { - return firstArgumentType.isInstance(firstArgument) && !isDisallowedNil(firstArgument); + return firstArgumentType.isInstance(firstArgument) && !isExcludedFirstArgumentType(firstArgument); } - private boolean isDisallowedNil(SExpression argument) { - return !isNilAcceptable && argument.isNull(); + private boolean isExcludedFirstArgumentType(SExpression firstArgument) { + return excludedFirstArgumentType != null && excludedFirstArgumentType.isInstance(firstArgument); } private void validateTrailingArguments(Cons argumentList) { @@ -132,7 +143,11 @@ public class ArgumentValidator { } private boolean isExpectedTrailingArgumentType(SExpression trailingArgument) { - return trailingArgumentType.isInstance(trailingArgument) && !isDisallowedNil(trailingArgument); + return trailingArgumentType.isInstance(trailingArgument) && !isExcludedTrailingArgumentType(trailingArgument); + } + + private boolean isExcludedTrailingArgumentType(SExpression trailingArgument) { + return excludedTrailingArgumentType != null && excludedTrailingArgumentType.isInstance(trailingArgument); } public static class TooFewArgumentsException extends LispException { diff --git a/src/function/builtin/special/CASE.java b/src/function/builtin/special/CASE.java index fc85b97..8750131 100644 --- a/src/function/builtin/special/CASE.java +++ b/src/function/builtin/special/CASE.java @@ -17,7 +17,7 @@ public class CASE extends LispSpecialFunction { this.argumentValidator = new ArgumentValidator("CASE"); this.argumentValidator.setMinimumNumberOfArguments(1); this.argumentValidator.setTrailingArgumentExpectedType(Cons.class); - this.argumentValidator.doNotAcceptNil(); + this.argumentValidator.setTrailingArgumentExcludedType(Nil.class); } public SExpression call(Cons argumentList) { diff --git a/src/function/builtin/special/COND.java b/src/function/builtin/special/COND.java index b34f1c7..5ec47c7 100644 --- a/src/function/builtin/special/COND.java +++ b/src/function/builtin/special/COND.java @@ -14,7 +14,7 @@ public class COND extends LispSpecialFunction { public COND() { this.argumentValidator = new ArgumentValidator("COND"); this.argumentValidator.setEveryArgumentExpectedType(Cons.class); - this.argumentValidator.doNotAcceptNil(); + this.argumentValidator.setEveryArgumentExcludedType(Nil.class); } public SExpression call(Cons argumentList) { diff --git a/test/function/ArgumentValidatorTester.java b/test/function/ArgumentValidatorTester.java index 5ea4969..2b7a8e6 100644 --- a/test/function/ArgumentValidatorTester.java +++ b/test/function/ArgumentValidatorTester.java @@ -74,46 +74,28 @@ public class ArgumentValidatorTester { } @Test - public void tooManyArgumentsException_HasCorrectSeverity() { + public void tooManyArgumentsException_HasCorrectAttributes() { TooManyArgumentsException e = new TooManyArgumentsException("TEST", NIL); assertEquals(ERROR, e.getSeverity()); - } - - @Test - public void tooManyArgumentsException_HasMessageText() { - TooManyArgumentsException e = new TooManyArgumentsException("TEST", NIL); - assertNotNull(e.getMessage()); assertTrue(e.getMessage().length() > 0); } @Test - public void tooFewArgumentsException_HasCorrectSeverity() { + public void tooFewArgumentsException_HasCorrectAttributes() { TooFewArgumentsException e = new TooFewArgumentsException("TEST", NIL); assertEquals(ERROR, e.getSeverity()); - } - - @Test - public void tooFewArgumentsException_HasMessageText() { - TooFewArgumentsException e = new TooFewArgumentsException("TEST", NIL); - assertNotNull(e.getMessage()); assertTrue(e.getMessage().length() > 0); } @Test - public void BadArgumentTypeException_HasCorrectSeverity() { + public void badArgumentTypeException_HasCorrectAttributes() { BadArgumentTypeException e = new BadArgumentTypeException("TEST", NIL, SExpression.class); assertEquals(ERROR, e.getSeverity()); - } - - @Test - public void BadArgumentTypeException_HasMessageText() { - BadArgumentTypeException e = new BadArgumentTypeException("TEST", NIL, SExpression.class); - assertNotNull(e.getMessage()); assertTrue(e.getMessage().length() > 0); } @@ -201,22 +183,40 @@ public class ArgumentValidatorTester { assertTrue(e.getMessage().length() > 0); } - @Test(expected = BadArgumentTypeException.class) - public void doNotAcceptNil_ThrowsExceptionOnNilArgument() { - validator.doNotAcceptNil(); + @Test + public void excludedFirstArgumentType_DoesNotAffectTrailingArguments() { + validator.setFirstArgumentExcludedType(Nil.class); validator.validate(new Cons(T, new Cons(NIL, NIL))); } @Test - public void doNotAcceptNil_AllowsEmptyArgumentList() { - validator.doNotAcceptNil(); - validator.validate(NIL); + public void excludedTrailingArgumentType_DoesNotAffectFirstArgument() { + validator.setTrailingArgumentExcludedType(Nil.class); + validator.validate(new Cons(NIL, new Cons(T, NIL))); } - @Test - public void doNotAcceptNil_AllowsProperList() { - validator.doNotAcceptNil(); - validator.validate(new Cons(T, new Cons(T, NIL))); + @Test(expected = BadArgumentTypeException.class) + public void excludedFirstArgumentType_ThrowsException() { + validator.setFirstArgumentExcludedType(Nil.class); + validator.validate(new Cons(NIL, new Cons(T, NIL))); + } + + @Test(expected = BadArgumentTypeException.class) + public void excludedTrailingArgumentType_ThrowsException() { + validator.setTrailingArgumentExcludedType(Nil.class); + validator.validate(new Cons(T, new Cons(NIL, NIL))); + } + + @Test(expected = BadArgumentTypeException.class) + public void excludedArgumentType_ThrowsExceptionOnFirstArgument() { + validator.setEveryArgumentExcludedType(Nil.class); + validator.validate(new Cons(NIL, new Cons(T, NIL))); + } + + @Test(expected = BadArgumentTypeException.class) + public void excludedArgumentType_ThrowsExceptionOnTrailingArgument() { + validator.setEveryArgumentExcludedType(Nil.class); + validator.validate(new Cons(T, new Cons(NIL, NIL))); } }