Convert Cond to kotlin
This commit is contained in:
		
							parent
							
								
									5d1606571a
								
							
						
					
					
						commit
						c6d25275bb
					
				| @ -1,67 +0,0 @@ | ||||
| package function.builtin.special; | ||||
| 
 | ||||
| import function.ArgumentValidator; | ||||
| import function.FunctionNames; | ||||
| import function.LispSpecialFunction; | ||||
| import recursion.TailCall; | ||||
| import sexpression.Cons; | ||||
| import sexpression.Nil; | ||||
| import sexpression.SExpression; | ||||
| 
 | ||||
| import static function.builtin.Eval.eval; | ||||
| import static recursion.TailCalls.done; | ||||
| import static recursion.TailCalls.tailCall; | ||||
| 
 | ||||
| @FunctionNames({ "COND" }) | ||||
| public class COND extends LispSpecialFunction { | ||||
| 
 | ||||
|     private ArgumentValidator argumentValidator; | ||||
| 
 | ||||
|     public COND(String name) { | ||||
|         this.argumentValidator = new ArgumentValidator(name); | ||||
|         this.argumentValidator.setEveryArgumentExpectedType(Cons.class); | ||||
|         this.argumentValidator.setEveryArgumentExcludedType(Nil.class); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public SExpression call(Cons argumentList) { | ||||
|         argumentValidator.validate(argumentList); | ||||
| 
 | ||||
|         return callTailRecursive(argumentList).invoke(); | ||||
|     } | ||||
| 
 | ||||
|     private TailCall<SExpression> callTailRecursive(Cons argumentList) { | ||||
|         if (argumentList.isNull()) | ||||
|             return done(Nil.INSTANCE); | ||||
| 
 | ||||
|         Cons clause = (Cons) argumentList.getFirst(); | ||||
|         Cons remainingClauses = (Cons) argumentList.getRest(); | ||||
|         SExpression test = eval(clause.getFirst()); | ||||
| 
 | ||||
|         if (isTestSuccessful(test)) | ||||
|             return done(evaluateConsequents(clause.getRest(), test)); | ||||
| 
 | ||||
|         return tailCall(() -> callTailRecursive(remainingClauses)); | ||||
|     } | ||||
| 
 | ||||
|     private boolean isTestSuccessful(SExpression test) { | ||||
|         return test != Nil.INSTANCE; | ||||
|     } | ||||
| 
 | ||||
|     private SExpression evaluateConsequents(SExpression consequentList, SExpression test) { | ||||
|         SExpression lastConsequentValue = test; | ||||
| 
 | ||||
|         for (; consequentList.isCons(); consequentList = advanceCons(consequentList)) | ||||
|             lastConsequentValue = eval(getFirst(consequentList)); | ||||
| 
 | ||||
|         return lastConsequentValue; | ||||
|     } | ||||
| 
 | ||||
|     private SExpression advanceCons(SExpression knownCons) { | ||||
|         return ((Cons) knownCons).getRest(); | ||||
|     } | ||||
| 
 | ||||
|     private SExpression getFirst(SExpression knownCons) { | ||||
|         return ((Cons) knownCons).getFirst(); | ||||
|     } | ||||
| } | ||||
| @ -57,5 +57,5 @@ class Case(name: String) : LispSpecialFunction() { | ||||
|     } | ||||
| 
 | ||||
|     private fun evaluateConsequents(clause: Cons) = | ||||
|         clause.drop(1).fold(Nil as SExpression) { _, it -> eval(it.first) } | ||||
|         clause.drop(1).fold(Nil as SExpression) { _, cons -> eval(cons.first) } | ||||
| } | ||||
|  | ||||
							
								
								
									
										41
									
								
								src/main/kotlin/function/builtin/special/Cond.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/main/kotlin/function/builtin/special/Cond.kt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,41 @@ | ||||
| package function.builtin.special | ||||
| 
 | ||||
| import function.ArgumentValidator | ||||
| import function.FunctionNames | ||||
| import function.LispSpecialFunction | ||||
| import function.builtin.Eval.Companion.eval | ||||
| import sexpression.Cons | ||||
| import sexpression.Nil | ||||
| import sexpression.SExpression | ||||
| 
 | ||||
| @FunctionNames("COND") | ||||
| class Cond(name: String) : LispSpecialFunction() { | ||||
| 
 | ||||
|     private val argumentValidator = ArgumentValidator(name).apply { | ||||
|         setEveryArgumentExpectedType(Cons::class.java) | ||||
|         setEveryArgumentExcludedType(Nil::class.java) | ||||
|     } | ||||
| 
 | ||||
|     override fun call(argumentList: Cons): SExpression { | ||||
|         argumentValidator.validate(argumentList) | ||||
| 
 | ||||
|         return callTailRecursive(argumentList) | ||||
|     } | ||||
| 
 | ||||
|     private tailrec fun callTailRecursive(argumentList: Cons): SExpression { | ||||
|         if (argumentList.isNull) | ||||
|             return Nil | ||||
| 
 | ||||
|         val clause = argumentList.first as Cons | ||||
|         val remainingClauses = argumentList.rest as Cons | ||||
|         val test = eval(clause.first) | ||||
| 
 | ||||
|         return if (!test.isNull) | ||||
|             evaluateConsequents(clause, test) | ||||
|         else | ||||
|             callTailRecursive(remainingClauses) | ||||
|     } | ||||
| 
 | ||||
|     private fun evaluateConsequents(clause: Cons, test: SExpression) = | ||||
|         clause.drop(1).fold(test) { _, cons -> eval(cons.first) } | ||||
| } | ||||
| @ -1,96 +0,0 @@ | ||||
| package function.builtin.special; | ||||
| 
 | ||||
| import function.ArgumentValidator.BadArgumentTypeException; | ||||
| import function.ArgumentValidator.DottedArgumentListException; | ||||
| import org.junit.Test; | ||||
| import testutil.SymbolAndFunctionCleaner; | ||||
| 
 | ||||
| import static testutil.TestUtilities.assertSExpressionsMatch; | ||||
| import static testutil.TestUtilities.evaluateString; | ||||
| import static testutil.TestUtilities.parseString; | ||||
| 
 | ||||
| public class CONDTest extends SymbolAndFunctionCleaner { | ||||
| 
 | ||||
|     @Test | ||||
|     public void condWithNoArguments() { | ||||
|         String input = "(cond)"; | ||||
| 
 | ||||
|         assertSExpressionsMatch(parseString("nil"), evaluateString(input)); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void condWithTrue() { | ||||
|         String input = "(cond (T))"; | ||||
| 
 | ||||
|         assertSExpressionsMatch(parseString("T"), evaluateString(input)); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void condWithNumber() { | ||||
|         String input = "(cond ((+ 1 2)))"; | ||||
| 
 | ||||
|         assertSExpressionsMatch(parseString("3"), evaluateString(input)); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void condWithSingleClause() { | ||||
|         String input = "(cond (T \"true\"))"; | ||||
| 
 | ||||
|         assertSExpressionsMatch(parseString("\"true\""), evaluateString(input)); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void condWithMultipleClauses() { | ||||
|         String input = "(cond ((= 1 2) 2) ((= 1 2) 2) ((= 1 1) 3))"; | ||||
| 
 | ||||
|         assertSExpressionsMatch(parseString("3"), evaluateString(input)); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void condWithMultipleTrueTests_ReturnsFirstOne() { | ||||
|         String input = "(cond ((= 1 1) 2) ((= 1 1) 3))"; | ||||
| 
 | ||||
|         assertSExpressionsMatch(parseString("2"), evaluateString(input)); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void condWithMultipleTrueTests_OnlyEvaluatesFirstOne() { | ||||
|         String input = "(cond ((= 1 1) 2) ((= 1 1) x))"; | ||||
| 
 | ||||
|         assertSExpressionsMatch(parseString("2"), evaluateString(input)); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void condWithMultipleValuesInConsequent_OnlyReturnsLast() { | ||||
|         String input = "(cond ((= 1 1) 2 3 4))"; | ||||
| 
 | ||||
|         assertSExpressionsMatch(parseString("4"), evaluateString(input)); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void condWithNoTrueTest_ReturnsNil() { | ||||
|         String input = "(cond ((= 1 2) T) ((= 1 3) T))"; | ||||
| 
 | ||||
|         assertSExpressionsMatch(parseString("nil"), evaluateString(input)); | ||||
|     } | ||||
| 
 | ||||
|     @Test(expected = BadArgumentTypeException.class) | ||||
|     public void condWithEmptyListArgument_ThrowsException() { | ||||
|         evaluateString("(cond ())"); | ||||
|     } | ||||
| 
 | ||||
|     @Test(expected = BadArgumentTypeException.class) | ||||
|     public void condWithNilArgument_ThrowsException() { | ||||
|         evaluateString("(cond nil)"); | ||||
|     } | ||||
| 
 | ||||
|     @Test(expected = BadArgumentTypeException.class) | ||||
|     public void condWithNonListArgument_ThrowsException() { | ||||
|         evaluateString("(cond o)"); | ||||
|     } | ||||
| 
 | ||||
|     @Test(expected = DottedArgumentListException.class) | ||||
|     public void condWithDottedArgumentList_ThrowsException() { | ||||
|         evaluateString("(apply 'cond (cons '(nil T) 'b))"); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										114
									
								
								src/test/kotlin/function/builtin/special/CondTest.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								src/test/kotlin/function/builtin/special/CondTest.kt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,114 @@ | ||||
| package function.builtin.special | ||||
| 
 | ||||
| import function.ArgumentValidator.BadArgumentTypeException | ||||
| import function.ArgumentValidator.DottedArgumentListException | ||||
| import org.junit.jupiter.api.Assertions.assertThrows | ||||
| import org.junit.jupiter.api.Test | ||||
| import testutil.LispTestInstance | ||||
| import testutil.SymbolAndFunctionCleaner | ||||
| 
 | ||||
| import testutil.TestUtilities.assertSExpressionsMatch | ||||
| import testutil.TestUtilities.evaluateString | ||||
| import testutil.TestUtilities.parseString | ||||
| 
 | ||||
| @LispTestInstance | ||||
| class CondTest : SymbolAndFunctionCleaner() { | ||||
| 
 | ||||
|     @Test | ||||
|     fun condWithNoArguments() { | ||||
|         val input = "(cond)" | ||||
| 
 | ||||
|         assertSExpressionsMatch(parseString("nil"), evaluateString(input)) | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     fun condWithTrue() { | ||||
|         val input = "(cond (T))" | ||||
| 
 | ||||
|         assertSExpressionsMatch(parseString("T"), evaluateString(input)) | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     fun condWithNumber() { | ||||
|         val input = "(cond ((+ 1 2)))" | ||||
| 
 | ||||
|         assertSExpressionsMatch(parseString("3"), evaluateString(input)) | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     fun condWithSingleClause() { | ||||
|         val input = "(cond (T \"true\"))" | ||||
| 
 | ||||
|         assertSExpressionsMatch(parseString("\"true\""), evaluateString(input)) | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     fun condWithMultipleClauses() { | ||||
|         val input = "(cond ((= 1 2) 2) ((= 1 2) 2) ((= 1 1) 3))" | ||||
| 
 | ||||
|         assertSExpressionsMatch(parseString("3"), evaluateString(input)) | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     fun condWithMultipleTrueTests_ReturnsFirstOne() { | ||||
|         val input = "(cond ((= 1 1) 2) ((= 1 1) 3))" | ||||
| 
 | ||||
|         assertSExpressionsMatch(parseString("2"), evaluateString(input)) | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     fun condWithMultipleTrueTests_OnlyEvaluatesFirstOne() { | ||||
|         val input = "(cond ((= 1 1) 2) ((= 1 1) x))" | ||||
| 
 | ||||
|         assertSExpressionsMatch(parseString("2"), evaluateString(input)) | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     fun condWithMultipleValuesInConsequent_OnlyReturnsLast() { | ||||
|         val input = "(cond ((= 1 1) 2 3 4))" | ||||
| 
 | ||||
|         assertSExpressionsMatch(parseString("4"), evaluateString(input)) | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     fun condWithNoTrueTest_ReturnsNil() { | ||||
|         val input = "(cond ((= 1 2) T) ((= 1 3) T))" | ||||
| 
 | ||||
|         assertSExpressionsMatch(parseString("nil"), evaluateString(input)) | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     fun condWithEmptyListArgument_ThrowsException() { | ||||
|         assertThrows(BadArgumentTypeException::class.java) { | ||||
|             evaluateString("(cond ())") | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     fun condWithNilArgument_ThrowsException() { | ||||
|         assertThrows(BadArgumentTypeException::class.java) { | ||||
|             evaluateString("(cond nil)") | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     fun condWithNonListArgument_ThrowsException() { | ||||
|         assertThrows(BadArgumentTypeException::class.java) { | ||||
|             evaluateString("(cond o)") | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     fun condWithDottedArgumentList_ThrowsException() { | ||||
|         assertThrows(DottedArgumentListException::class.java) { | ||||
|             evaluateString("(apply 'cond (cons '(nil T) 'b))") | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     fun condWithDottedClause() { | ||||
|         val input = "(eval `(cond ,(cons T 'pear)))" | ||||
| 
 | ||||
|         assertSExpressionsMatch(parseString("T"), evaluateString(input)) | ||||
|     } | ||||
| } | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user