Improved the argument list validation for COND
This commit is contained in:
		
							parent
							
								
									eb9f224c60
								
							
						
					
					
						commit
						37bc303fe8
					
				| @ -13,6 +13,7 @@ public class ArgumentValidator { | |||||||
|     private String functionName; |     private String functionName; | ||||||
|     private Integer maximumNumberOfArguments; |     private Integer maximumNumberOfArguments; | ||||||
|     private Integer minimumNumberOfArguments; |     private Integer minimumNumberOfArguments; | ||||||
|  |     private boolean isNilAcceptable; | ||||||
| 
 | 
 | ||||||
|     public ArgumentValidator(String functionName) { |     public ArgumentValidator(String functionName) { | ||||||
|         this.firstArgumentType = SExpression.class; |         this.firstArgumentType = SExpression.class; | ||||||
| @ -20,6 +21,7 @@ public class ArgumentValidator { | |||||||
|         this.functionName = functionName; |         this.functionName = functionName; | ||||||
|         this.minimumNumberOfArguments = null; |         this.minimumNumberOfArguments = null; | ||||||
|         this.maximumNumberOfArguments = null; |         this.maximumNumberOfArguments = null; | ||||||
|  |         this.isNilAcceptable = true; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public void setFirstArgumentExpectedType(Class<? extends SExpression> argumentType) { |     public void setFirstArgumentExpectedType(Class<? extends SExpression> argumentType) { | ||||||
| @ -48,6 +50,10 @@ public class ArgumentValidator { | |||||||
|         this.maximumNumberOfArguments = exactNumberOfArguments; |         this.maximumNumberOfArguments = exactNumberOfArguments; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public void doNotAcceptNil() { | ||||||
|  |         this.isNilAcceptable = false; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public void validate(Cons argumentList) { |     public void validate(Cons argumentList) { | ||||||
|         validateListNotDotted(argumentList); |         validateListNotDotted(argumentList); | ||||||
|         validateListLength(argumentList); |         validateListLength(argumentList); | ||||||
| @ -80,29 +86,35 @@ public class ArgumentValidator { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private void validateArgumentTypes(Cons argumentList) { |     private void validateArgumentTypes(Cons argumentList) { | ||||||
|         if (!isExpectedFirstArgumentType(argumentList.getCar())) |         validateFirstArgument(argumentList); | ||||||
|             throw new BadArgumentTypeException(functionName, argumentList.getCar(), firstArgumentType); |         validateTrailingArguments(argumentList); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|         validateRemainingArguments(argumentList); |     private void validateFirstArgument(Cons argumentList) { | ||||||
|  |         if (!isFirstArgumentValid(argumentList)) | ||||||
|  |             throw new BadArgumentTypeException(functionName, argumentList.getCar(), firstArgumentType); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private boolean isFirstArgumentValid(Cons argumentList) { | ||||||
|  |         return argumentList.nullp() || isExpectedFirstArgumentType(argumentList.getCar()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private boolean isExpectedFirstArgumentType(SExpression firstArgument) { |     private boolean isExpectedFirstArgumentType(SExpression firstArgument) { | ||||||
|         return firstArgumentType.isInstance(firstArgument); |         return firstArgumentType.isInstance(firstArgument) && !isDisallowedNil(firstArgument); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private void validateRemainingArguments(Cons cons) { |     private boolean isDisallowedNil(SExpression argument) { | ||||||
|         for (cons = (Cons) cons.getCdr(); !cons.nullp(); cons = (Cons) cons.getCdr()) |         return !isNilAcceptable && argument.nullp(); | ||||||
|             if (!isExpectedRemainingArgumentType(cons.getCar())) |     } | ||||||
|  | 
 | ||||||
|  |     private void validateTrailingArguments(Cons argumentList) { | ||||||
|  |         for (Cons cons = (Cons) argumentList.getCdr(); !cons.nullp(); cons = (Cons) cons.getCdr()) | ||||||
|  |             if (!isExpectedTrailingArgumentType(cons.getCar())) | ||||||
|                 throw new BadArgumentTypeException(functionName, cons.getCar(), trailingArgumentType); |                 throw new BadArgumentTypeException(functionName, cons.getCar(), trailingArgumentType); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private boolean isExpectedRemainingArgumentType(SExpression remainingArgument) { |     private boolean isExpectedTrailingArgumentType(SExpression trailingArgument) { | ||||||
|         return trailingArgumentType.isInstance(remainingArgument); |         return trailingArgumentType.isInstance(trailingArgument) && !isDisallowedNil(trailingArgument); | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public void validateListIsNotNil(Cons list) { |  | ||||||
|         if (list.nullp()) |  | ||||||
|             throw new BadArgumentTypeException(functionName, Nil.getUniqueInstance(), Cons.class); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public static class TooFewArgumentsException extends LispException { |     public static class TooFewArgumentsException extends LispException { | ||||||
|  | |||||||
| @ -10,6 +10,7 @@ public class COND extends LispFunction { | |||||||
|     public COND() { |     public COND() { | ||||||
|         this.argumentValidator = new ArgumentValidator("COND"); |         this.argumentValidator = new ArgumentValidator("COND"); | ||||||
|         this.argumentValidator.setEveryArgumentExpectedType(Cons.class); |         this.argumentValidator.setEveryArgumentExpectedType(Cons.class); | ||||||
|  |         this.argumentValidator.doNotAcceptNil(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public SExpression call(Cons argumentList) { |     public SExpression call(Cons argumentList) { | ||||||
| @ -22,7 +23,7 @@ public class COND extends LispFunction { | |||||||
|         if (argumentList.nullp()) |         if (argumentList.nullp()) | ||||||
|             return Nil.getUniqueInstance(); |             return Nil.getUniqueInstance(); | ||||||
| 
 | 
 | ||||||
|         Cons clause = getFirstClauseAndValidateNotNil(argumentList); |         Cons clause = (Cons) argumentList.getCar(); | ||||||
|         Cons remainingClauses = (Cons) argumentList.getCdr(); |         Cons remainingClauses = (Cons) argumentList.getCdr(); | ||||||
|         SExpression test = EVAL.eval(clause.getCar()); |         SExpression test = EVAL.eval(clause.getCar()); | ||||||
| 
 | 
 | ||||||
| @ -32,13 +33,6 @@ public class COND extends LispFunction { | |||||||
|         return callTailRecursive(remainingClauses); |         return callTailRecursive(remainingClauses); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private Cons getFirstClauseAndValidateNotNil(Cons argumentList) { |  | ||||||
|         Cons firstClause = (Cons) argumentList.getCar(); |  | ||||||
|         argumentValidator.validateListIsNotNil(firstClause); |  | ||||||
| 
 |  | ||||||
|         return firstClause; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private boolean isTestSuccessful(SExpression test) { |     private boolean isTestSuccessful(SExpression test) { | ||||||
|         return test != Nil.getUniqueInstance(); |         return test != Nil.getUniqueInstance(); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -200,13 +200,21 @@ public class ArgumentValidatorTester { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Test(expected = BadArgumentTypeException.class) |     @Test(expected = BadArgumentTypeException.class) | ||||||
|     public void validateListNotNil_ThrowsExceptionWithNilValue() { |     public void doNotAcceptNil_ThrowsExceptionOnNilArgument() { | ||||||
|         validator.validateListIsNotNil(Nil.getUniqueInstance()); |         validator.doNotAcceptNil(); | ||||||
|  |         validator.validate(new Cons(Symbol.T, new Cons(Nil.getUniqueInstance(), Nil.getUniqueInstance()))); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
|     public void validateListNotNil_DoesNotThrowExceptionWithNonNilValue() { |     public void doNotAcceptNil_AllowsEmptyArgumentList() { | ||||||
|         validator.validateListIsNotNil(new Cons(Nil.getUniqueInstance(), Nil.getUniqueInstance())); |         validator.doNotAcceptNil(); | ||||||
|  |         validator.validate(Nil.getUniqueInstance()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void doNotAcceptNil_AllowsProperList() { | ||||||
|  |         validator.doNotAcceptNil(); | ||||||
|  |         validator.validate(new Cons(Symbol.T, new Cons(Symbol.T, Nil.getUniqueInstance()))); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -58,4 +58,9 @@ public class APPLYTester { | |||||||
|         evaluateString("(apply '1)"); |         evaluateString("(apply '1)"); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     @Test(expected = DottedArgumentListException.class) | ||||||
|  |     public void testCondWithDottedArgumentList_ThrowsException() { | ||||||
|  |         evaluateString("(apply 'apply (cons 'T 'T))"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -4,7 +4,7 @@ import static testutil.TestUtilities.*; | |||||||
| 
 | 
 | ||||||
| import org.junit.Test; | import org.junit.Test; | ||||||
| 
 | 
 | ||||||
| import function.ArgumentValidator.BadArgumentTypeException; | import function.ArgumentValidator.*; | ||||||
| 
 | 
 | ||||||
| public class CONDTester { | public class CONDTester { | ||||||
| 
 | 
 | ||||||
| @ -74,4 +74,9 @@ public class CONDTester { | |||||||
|         evaluateString("(cond o)"); |         evaluateString("(cond o)"); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     @Test(expected = DottedArgumentListException.class) | ||||||
|  |     public void testCondWithDottedArgumentList_ThrowsException() { | ||||||
|  |         evaluateString("(apply 'cond (cons '(nil T) 'b))"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user