Convert Case to kotlin
This commit is contained in:
parent
8ca2eb199c
commit
9998a88569
11
pom.xml
11
pom.xml
|
@ -8,9 +8,18 @@
|
||||||
<artifactId>transcendental-lisp</artifactId>
|
<artifactId>transcendental-lisp</artifactId>
|
||||||
<version>1.2.1</version>
|
<version>1.2.1</version>
|
||||||
|
|
||||||
|
<!-- TODO - remove after kotlin 1.3 is released -->
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>kotlin-eap</id>
|
||||||
|
<name>Kotlin EAP</name>
|
||||||
|
<url>https://dl.bintray.com/kotlin/kotlin-eap</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<kotlin.version>1.2.71</kotlin.version>
|
<kotlin.version>1.3.0-rc-190</kotlin.version>
|
||||||
<junit5.version>5.3.1</junit5.version>
|
<junit5.version>5.3.1</junit5.version>
|
||||||
<skipTests>false</skipTests>
|
<skipTests>false</skipTests>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
|
@ -1,84 +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 sexpression.Symbol;
|
|
||||||
|
|
||||||
import static function.builtin.Eval.eval;
|
|
||||||
import static function.builtin.predicate.EQUAL.isEqual;
|
|
||||||
import static recursion.TailCalls.done;
|
|
||||||
import static recursion.TailCalls.tailCall;
|
|
||||||
|
|
||||||
@FunctionNames({ "CASE" })
|
|
||||||
public class CASE extends LispSpecialFunction {
|
|
||||||
|
|
||||||
private ArgumentValidator argumentValidator;
|
|
||||||
|
|
||||||
public CASE(String name) {
|
|
||||||
this.argumentValidator = new ArgumentValidator(name);
|
|
||||||
this.argumentValidator.setMinimumNumberOfArguments(1);
|
|
||||||
this.argumentValidator.setTrailingArgumentExpectedType(Cons.class);
|
|
||||||
this.argumentValidator.setTrailingArgumentExcludedType(Nil.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SExpression call(Cons argumentList) {
|
|
||||||
argumentValidator.validate(argumentList);
|
|
||||||
SExpression key = eval(argumentList.getFirst());
|
|
||||||
|
|
||||||
return callTailRecursive(key, (Cons) argumentList.getRest()).invoke();
|
|
||||||
}
|
|
||||||
|
|
||||||
private TailCall<SExpression> callTailRecursive(SExpression key, Cons argumentList) {
|
|
||||||
if (argumentList.isNull())
|
|
||||||
return done(Nil.INSTANCE);
|
|
||||||
|
|
||||||
Cons clause = (Cons) argumentList.getFirst();
|
|
||||||
Cons remainingClauses = (Cons) argumentList.getRest();
|
|
||||||
SExpression keyList = clause.getFirst();
|
|
||||||
|
|
||||||
if (isMatch(key, keyList))
|
|
||||||
return done(evaluateConsequents(clause.getRest()));
|
|
||||||
|
|
||||||
return tailCall(() -> callTailRecursive(key, remainingClauses));
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isMatch(SExpression key, SExpression keyList) {
|
|
||||||
if (keyList.isNull())
|
|
||||||
return false;
|
|
||||||
else if (keyList.isCons())
|
|
||||||
return containsMatch(key, keyList);
|
|
||||||
|
|
||||||
return isEqual(key, keyList) || isEqual(Symbol.Companion.getT(), keyList);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean containsMatch(SExpression key, SExpression keyList) {
|
|
||||||
for (; keyList.isCons(); keyList = advanceCons(keyList))
|
|
||||||
if (isEqual(key, getFirst(keyList)))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private SExpression advanceCons(SExpression knownCons) {
|
|
||||||
return ((Cons) knownCons).getRest();
|
|
||||||
}
|
|
||||||
|
|
||||||
private SExpression getFirst(SExpression knownCons) {
|
|
||||||
return ((Cons) knownCons).getFirst();
|
|
||||||
}
|
|
||||||
|
|
||||||
private SExpression evaluateConsequents(SExpression consequentList) {
|
|
||||||
SExpression lastConsequentValue = Nil.INSTANCE;
|
|
||||||
|
|
||||||
for (; consequentList.isCons(); consequentList = advanceCons(consequentList))
|
|
||||||
lastConsequentValue = eval(getFirst(consequentList));
|
|
||||||
|
|
||||||
return lastConsequentValue;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
package function.builtin.special
|
||||||
|
|
||||||
|
import function.ArgumentValidator
|
||||||
|
import function.FunctionNames
|
||||||
|
import function.LispSpecialFunction
|
||||||
|
import function.builtin.Eval.Companion.eval
|
||||||
|
import function.builtin.predicate.EQUAL.isEqual
|
||||||
|
import sexpression.Cons
|
||||||
|
import sexpression.Nil
|
||||||
|
import sexpression.SExpression
|
||||||
|
import sexpression.Symbol
|
||||||
|
|
||||||
|
@FunctionNames("CASE")
|
||||||
|
class Case(name: String) : LispSpecialFunction() {
|
||||||
|
|
||||||
|
private val argumentValidator = ArgumentValidator(name).apply {
|
||||||
|
setMinimumNumberOfArguments(1)
|
||||||
|
setTrailingArgumentExpectedType(Cons::class.java)
|
||||||
|
setTrailingArgumentExcludedType(Nil::class.java)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun call(argumentList: Cons): SExpression {
|
||||||
|
argumentValidator.validate(argumentList)
|
||||||
|
val key = eval(argumentList.first)
|
||||||
|
|
||||||
|
return callTailRecursive(key, argumentList.rest as Cons)
|
||||||
|
}
|
||||||
|
|
||||||
|
private tailrec fun callTailRecursive(key: SExpression, argumentList: Cons): SExpression {
|
||||||
|
if (argumentList.isNull)
|
||||||
|
return Nil
|
||||||
|
|
||||||
|
val clause = argumentList.first as Cons
|
||||||
|
val remainingClauses = argumentList.rest as Cons
|
||||||
|
val keyList = clause.first
|
||||||
|
|
||||||
|
return if (isMatch(key, keyList))
|
||||||
|
evaluateConsequents(clause.rest)
|
||||||
|
else
|
||||||
|
callTailRecursive(key, remainingClauses)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isMatch(key: SExpression, keyList: SExpression) = when {
|
||||||
|
keyList.isNull -> false
|
||||||
|
keyList.isCons -> containsMatch(key, keyList)
|
||||||
|
else -> isEqual(key, keyList) || isEqual(Symbol.T, keyList)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun containsMatch(key: SExpression, keyList: SExpression): Boolean {
|
||||||
|
if (keyList.isCons) {
|
||||||
|
(keyList as Cons).forEach {
|
||||||
|
if (isEqual(key, it.first)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun evaluateConsequents(consequentList: SExpression): SExpression {
|
||||||
|
var lastConsequentValue: SExpression = Nil
|
||||||
|
|
||||||
|
if (consequentList.isCons) {
|
||||||
|
(consequentList as Cons).forEach {
|
||||||
|
lastConsequentValue = eval(it.first)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return lastConsequentValue
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,196 +0,0 @@
|
||||||
package function.builtin.special;
|
|
||||||
|
|
||||||
import function.ArgumentValidator.BadArgumentTypeException;
|
|
||||||
import function.ArgumentValidator.TooFewArgumentsException;
|
|
||||||
import org.junit.Test;
|
|
||||||
import testutil.SymbolAndFunctionCleaner;
|
|
||||||
|
|
||||||
import static testutil.TestUtilities.assertSExpressionsMatch;
|
|
||||||
import static testutil.TestUtilities.evaluateString;
|
|
||||||
import static testutil.TestUtilities.parseString;
|
|
||||||
|
|
||||||
public class CASETest extends SymbolAndFunctionCleaner {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void caseWithKeyOnly() {
|
|
||||||
String input = "(case t)";
|
|
||||||
|
|
||||||
assertSExpressionsMatch(parseString("nil"), evaluateString(input));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void caseWithEmptyConsequent() {
|
|
||||||
String input = "(case :a ((:a)))";
|
|
||||||
|
|
||||||
assertSExpressionsMatch(parseString("nil"), evaluateString(input));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void caseWithOneClause_Match() {
|
|
||||||
String input = "(case :a ((:a) 'banana))";
|
|
||||||
|
|
||||||
assertSExpressionsMatch(parseString("banana"), evaluateString(input));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void caseWithOneClause_NoMatch() {
|
|
||||||
String input = "(case :a ((:b) 'banana))";
|
|
||||||
|
|
||||||
assertSExpressionsMatch(parseString("nil"), evaluateString(input));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void caseWithSeveralClauses_Match() {
|
|
||||||
String input = "(case :a ((:b) 'orange) ((:a) 'banana))";
|
|
||||||
|
|
||||||
assertSExpressionsMatch(parseString("banana"), evaluateString(input));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void caseWithSeveralClauses_NoMatch() {
|
|
||||||
String input = "(case :a ((:b) 'orange) ((:c) 'banana))";
|
|
||||||
|
|
||||||
assertSExpressionsMatch(parseString("nil"), evaluateString(input));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void caseWithSeveralItemsInKeyList_Match() {
|
|
||||||
String input = "(case :a ((:b :a) 'orange) ((:c :d) 'banana))";
|
|
||||||
|
|
||||||
assertSExpressionsMatch(parseString("orange"), evaluateString(input));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void caseWithSeveralItemsInKeyList_NoMatch() {
|
|
||||||
String input = "(case :a ((:b :f) 'orange) ((:c :d) 'banana))";
|
|
||||||
|
|
||||||
assertSExpressionsMatch(parseString("nil"), evaluateString(input));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void caseWithSymbolicKeyList_Match() {
|
|
||||||
String input = "(case :a (:a 'orange))";
|
|
||||||
|
|
||||||
assertSExpressionsMatch(parseString("orange"), evaluateString(input));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void caseWithSymbolicKeyList_NoMatch() {
|
|
||||||
String input = "(case :a (:b 'orange))";
|
|
||||||
|
|
||||||
assertSExpressionsMatch(parseString("nil"), evaluateString(input));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void caseDoesNotEvaluateKeyList() {
|
|
||||||
String input = "(case 'x ((x) t))";
|
|
||||||
|
|
||||||
assertSExpressionsMatch(parseString("t"), evaluateString(input));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void caseWithEmptyKeyList() {
|
|
||||||
String input = "(case nil (() 'orange))";
|
|
||||||
|
|
||||||
assertSExpressionsMatch(parseString("nil"), evaluateString(input));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void caseWithNil() {
|
|
||||||
String input = "(case nil ((nil) 'orange))";
|
|
||||||
|
|
||||||
assertSExpressionsMatch(parseString("orange"), evaluateString(input));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void caseWithEmptyList() {
|
|
||||||
String input = "(case () ((()) 'orange))";
|
|
||||||
|
|
||||||
assertSExpressionsMatch(parseString("orange"), evaluateString(input));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void caseWithList() {
|
|
||||||
String input = "(case '(5 4 3) (((1 2) (5 4 3)) 'orange))";
|
|
||||||
|
|
||||||
assertSExpressionsMatch(parseString("orange"), evaluateString(input));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void caseWithDefaultClause() {
|
|
||||||
String input = "(case nil (() 'banana) (t 'orange))";
|
|
||||||
|
|
||||||
assertSExpressionsMatch(parseString("orange"), evaluateString(input));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void caseWithOutOfOrderDefaultClause() {
|
|
||||||
String input = "(case :a (t 'orange) (:a 'banana))";
|
|
||||||
|
|
||||||
assertSExpressionsMatch(parseString("orange"), evaluateString(input));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void caseWithKeyListContainingT() {
|
|
||||||
String input = "(case t ((t) 'banana))";
|
|
||||||
|
|
||||||
assertSExpressionsMatch(parseString("banana"), evaluateString(input));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void caseWithMultipleMatches_ReturnsFirst() {
|
|
||||||
String input = "(case 2 ((0) 'banana) ((1) 'apple) ((2) 'avocado) ((2) 'greenbean))";
|
|
||||||
|
|
||||||
assertSExpressionsMatch(parseString("avocado"), evaluateString(input));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void caseEvaluatesMultipleConsequents() {
|
|
||||||
String input = "(case 2 (1 1) (2 (setq x 'x) (setq y 'y)) (3 3)))";
|
|
||||||
|
|
||||||
evaluateString(input);
|
|
||||||
|
|
||||||
assertSExpressionsMatch(parseString("x"), evaluateString("x"));
|
|
||||||
assertSExpressionsMatch(parseString("y"), evaluateString("y"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void caseReturnsValueOfLastConsequent() {
|
|
||||||
String input = "(case 2 (1 1) (2 3 4 5) (3 3))";
|
|
||||||
|
|
||||||
assertSExpressionsMatch(parseString("5"), evaluateString(input));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void caseOnlyEvaluatesConsequentInFirstMatchingClause() {
|
|
||||||
String input = "(case 2 ((0) (setq zero 0)) ((1) (setq one 1)) ((2) (setq two '2)) ((2) (setq two 'two)))";
|
|
||||||
|
|
||||||
evaluateString("(setq zero nil)");
|
|
||||||
evaluateString("(setq one nil)");
|
|
||||||
evaluateString(input);
|
|
||||||
|
|
||||||
assertSExpressionsMatch(parseString("nil"), evaluateString("zero"));
|
|
||||||
assertSExpressionsMatch(parseString("nil"), evaluateString("one"));
|
|
||||||
assertSExpressionsMatch(parseString("2"), evaluateString("two"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = TooFewArgumentsException.class)
|
|
||||||
public void caseWithTooFewArguments() {
|
|
||||||
evaluateString("(case)");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = BadArgumentTypeException.class)
|
|
||||||
public void caseWithNonListClause() {
|
|
||||||
evaluateString("(case :a t)");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = BadArgumentTypeException.class)
|
|
||||||
public void caseWithEmptyClause() {
|
|
||||||
evaluateString("(case :a ())");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = BadArgumentTypeException.class)
|
|
||||||
public void caseWithNilClause() {
|
|
||||||
evaluateString("(case :a nil)");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,206 @@
|
||||||
|
package function.builtin.special
|
||||||
|
|
||||||
|
import function.ArgumentValidator.BadArgumentTypeException
|
||||||
|
import function.ArgumentValidator.TooFewArgumentsException
|
||||||
|
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 CaseTest : SymbolAndFunctionCleaner() {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun caseWithKeyOnly() {
|
||||||
|
val input = "(case t)"
|
||||||
|
|
||||||
|
assertSExpressionsMatch(parseString("nil"), evaluateString(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun caseWithEmptyConsequent() {
|
||||||
|
val input = "(case :a ((:a)))"
|
||||||
|
|
||||||
|
assertSExpressionsMatch(parseString("nil"), evaluateString(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun caseWithOneClause_Match() {
|
||||||
|
val input = "(case :a ((:a) 'banana))"
|
||||||
|
|
||||||
|
assertSExpressionsMatch(parseString("banana"), evaluateString(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun caseWithOneClause_NoMatch() {
|
||||||
|
val input = "(case :a ((:b) 'banana))"
|
||||||
|
|
||||||
|
assertSExpressionsMatch(parseString("nil"), evaluateString(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun caseWithSeveralClauses_Match() {
|
||||||
|
val input = "(case :a ((:b) 'orange) ((:a) 'banana))"
|
||||||
|
|
||||||
|
assertSExpressionsMatch(parseString("banana"), evaluateString(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun caseWithSeveralClauses_NoMatch() {
|
||||||
|
val input = "(case :a ((:b) 'orange) ((:c) 'banana))"
|
||||||
|
|
||||||
|
assertSExpressionsMatch(parseString("nil"), evaluateString(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun caseWithSeveralItemsInKeyList_Match() {
|
||||||
|
val input = "(case :a ((:b :a) 'orange) ((:c :d) 'banana))"
|
||||||
|
|
||||||
|
assertSExpressionsMatch(parseString("orange"), evaluateString(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun caseWithSeveralItemsInKeyList_NoMatch() {
|
||||||
|
val input = "(case :a ((:b :f) 'orange) ((:c :d) 'banana))"
|
||||||
|
|
||||||
|
assertSExpressionsMatch(parseString("nil"), evaluateString(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun caseWithSymbolicKeyList_Match() {
|
||||||
|
val input = "(case :a (:a 'orange))"
|
||||||
|
|
||||||
|
assertSExpressionsMatch(parseString("orange"), evaluateString(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun caseWithSymbolicKeyList_NoMatch() {
|
||||||
|
val input = "(case :a (:b 'orange))"
|
||||||
|
|
||||||
|
assertSExpressionsMatch(parseString("nil"), evaluateString(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun caseDoesNotEvaluateKeyList() {
|
||||||
|
val input = "(case 'x ((x) t))"
|
||||||
|
|
||||||
|
assertSExpressionsMatch(parseString("t"), evaluateString(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun caseWithEmptyKeyList() {
|
||||||
|
val input = "(case nil (() 'orange))"
|
||||||
|
|
||||||
|
assertSExpressionsMatch(parseString("nil"), evaluateString(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun caseWithNil() {
|
||||||
|
val input = "(case nil ((nil) 'orange))"
|
||||||
|
|
||||||
|
assertSExpressionsMatch(parseString("orange"), evaluateString(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun caseWithEmptyList() {
|
||||||
|
val input = "(case () ((()) 'orange))"
|
||||||
|
|
||||||
|
assertSExpressionsMatch(parseString("orange"), evaluateString(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun caseWithList() {
|
||||||
|
val input = "(case '(5 4 3) (((1 2) (5 4 3)) 'orange))"
|
||||||
|
|
||||||
|
assertSExpressionsMatch(parseString("orange"), evaluateString(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun caseWithDefaultClause() {
|
||||||
|
val input = "(case nil (() 'banana) (t 'orange))"
|
||||||
|
|
||||||
|
assertSExpressionsMatch(parseString("orange"), evaluateString(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun caseWithOutOfOrderDefaultClause() {
|
||||||
|
val input = "(case :a (t 'orange) (:a 'banana))"
|
||||||
|
|
||||||
|
assertSExpressionsMatch(parseString("orange"), evaluateString(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun caseWithKeyListContainingT() {
|
||||||
|
val input = "(case t ((t) 'banana))"
|
||||||
|
|
||||||
|
assertSExpressionsMatch(parseString("banana"), evaluateString(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun caseWithMultipleMatches_ReturnsFirst() {
|
||||||
|
val input = "(case 2 ((0) 'banana) ((1) 'apple) ((2) 'avocado) ((2) 'greenbean))"
|
||||||
|
|
||||||
|
assertSExpressionsMatch(parseString("avocado"), evaluateString(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun caseEvaluatesMultipleConsequents() {
|
||||||
|
val input = "(case 2 (1 1) (2 (setq x 'x) (setq y 'y)) (3 3)))"
|
||||||
|
|
||||||
|
evaluateString(input)
|
||||||
|
|
||||||
|
assertSExpressionsMatch(parseString("x"), evaluateString("x"))
|
||||||
|
assertSExpressionsMatch(parseString("y"), evaluateString("y"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun caseReturnsValueOfLastConsequent() {
|
||||||
|
val input = "(case 2 (1 1) (2 3 4 5) (3 3))"
|
||||||
|
|
||||||
|
assertSExpressionsMatch(parseString("5"), evaluateString(input))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun caseOnlyEvaluatesConsequentInFirstMatchingClause() {
|
||||||
|
val input = "(case 2 ((0) (setq zero 0)) ((1) (setq one 1)) ((2) (setq two '2)) ((2) (setq two 'two)))"
|
||||||
|
|
||||||
|
evaluateString("(setq zero nil)")
|
||||||
|
evaluateString("(setq one nil)")
|
||||||
|
evaluateString(input)
|
||||||
|
|
||||||
|
assertSExpressionsMatch(parseString("nil"), evaluateString("zero"))
|
||||||
|
assertSExpressionsMatch(parseString("nil"), evaluateString("one"))
|
||||||
|
assertSExpressionsMatch(parseString("2"), evaluateString("two"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun caseWithTooFewArguments() {
|
||||||
|
assertThrows(TooFewArgumentsException::class.java) {
|
||||||
|
evaluateString("(case)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun caseWithNonListClause() {
|
||||||
|
assertThrows(BadArgumentTypeException::class.java) {
|
||||||
|
evaluateString("(case :a t)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun caseWithEmptyClause() {
|
||||||
|
assertThrows(BadArgumentTypeException::class.java) {
|
||||||
|
evaluateString("(case :a ())")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun caseWithNilClause() {
|
||||||
|
assertThrows(BadArgumentTypeException::class.java) {
|
||||||
|
evaluateString("(case :a nil)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue