Parts of CASE and COND were refactored

Updated the terminology used in the code
Added test cases
Changed the format of error/warning messages
This commit is contained in:
Mike Cifelli 2017-02-28 16:16:43 -05:00
parent 4253145383
commit 42191ec69d
5 changed files with 50 additions and 21 deletions

View File

@ -40,7 +40,7 @@ public class ErrorManager {
private String formatMessage(LispException lispException) {
Severity severity = lispException.getSeverity();
String prefix = severity.toDisplayString();
String message = MessageFormat.format("{0}: {1}", prefix, lispException.getMessage());
String message = MessageFormat.format("[{0}] {1}", prefix, lispException.getMessage());
return severity.decorate(message, environment);
}

View File

@ -34,7 +34,7 @@ public class CASE extends LispSpecialFunction {
SExpression keyList = clause.getFirst();
if (isMatch(key, keyList))
return evaluateResult(clause);
return evaluateConsequents(clause.getRest());
return callTailRecursive(key, remainingClauses);
}
@ -68,13 +68,13 @@ public class CASE extends LispSpecialFunction {
return ((Cons) knownCons).getFirst();
}
private SExpression evaluateResult(Cons clause) {
SExpression lastResultValue = Nil.getInstance();
private SExpression evaluateConsequents(SExpression consequentList) {
SExpression lastConsequentValue = Nil.getInstance();
for (SExpression result = clause.getRest(); result.isCons(); result = advanceCons(result))
lastResultValue = eval(getFirst(result));
for (; consequentList.isCons(); consequentList = advanceCons(consequentList))
lastConsequentValue = eval(getFirst(consequentList));
return lastResultValue;
return lastConsequentValue;
}
}

View File

@ -31,7 +31,7 @@ public class COND extends LispSpecialFunction {
SExpression test = eval(clause.getFirst());
if (isTestSuccessful(test))
return evaluateResult(clause, test);
return evaluateConsequents(clause.getRest(), test);
return callTailRecursive(remainingClauses);
}
@ -40,13 +40,13 @@ public class COND extends LispSpecialFunction {
return test != Nil.getInstance();
}
private SExpression evaluateResult(Cons clause, SExpression test) {
SExpression lastResultValue = test;
private SExpression evaluateConsequents(SExpression consequentList, SExpression test) {
SExpression lastConsequentValue = test;
for (SExpression result = clause.getRest(); result.isCons(); result = advanceCons(result))
lastResultValue = eval(getFirst(result));
for (; consequentList.isCons(); consequentList = advanceCons(consequentList))
lastConsequentValue = eval(getFirst(consequentList));
return lastResultValue;
return lastConsequentValue;
}
private SExpression advanceCons(SExpression knownCons) {

View File

@ -26,7 +26,7 @@ public class CASETester {
}
@Test
public void caseWithOnlySwitchExpression() {
public void caseWithKeyOnly() {
String input = "(case t)";
assertSExpressionsMatch(parseString("nil"), evaluateString(input));
@ -95,6 +95,13 @@ public class CASETester {
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))";
@ -138,7 +145,24 @@ public class CASETester {
}
@Test
public void caseOnlyEvaluatesFirstMatchingClause() {
public void caseEvaluatesMultipleConsequents() {
String input = "(case 2 (1 1) (2 (setf x 'x) (setf 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) (setf zero 0)) ((1) (setf one 1)) ((2) (setf two '2)) ((2) (setf two 'two)))";
evaluateString("(setf zero nil)");
@ -160,4 +184,9 @@ public class CASETester {
evaluateString("(case :a t)");
}
@Test(expected = BadArgumentTypeException.class)
public void caseWithNilClause() {
evaluateString("(case :a ())");
}
}

View File

@ -30,42 +30,42 @@ public class CONDTester {
}
@Test
public void condWithSingleExpression() {
public void condWithSingleClause() {
String input = "(cond (T \"true\"))";
assertSExpressionsMatch(parseString("\"true\""), evaluateString(input));
}
@Test
public void condWithMultipleExpressions() {
public void condWithMultipleClauses() {
String input = "(cond ((= 1 2) 2) ((= 1 2) 2) ((= 1 1) 3))";
assertSExpressionsMatch(parseString("3"), evaluateString(input));
}
@Test
public void condWithMultipleConditionsMatching_ReturnFirstOne() {
public void condWithMultipleTrueTests_ReturnsFirstOne() {
String input = "(cond ((= 1 1) 2) ((= 1 1) 3))";
assertSExpressionsMatch(parseString("2"), evaluateString(input));
}
@Test
public void condWithMultipleConditionsMatching_OnlyEvaluatesFirstOne() {
public void condWithMultipleTrueTests_OnlyEvaluatesFirstOne() {
String input = "(cond ((= 1 1) 2) ((= 1 1) x))";
assertSExpressionsMatch(parseString("2"), evaluateString(input));
}
@Test
public void condWithMultipleResultValues_OnlyReturnsLast() {
public void condWithMultipleValuesInConsequent_OnlyReturnsLast() {
String input = "(cond ((= 1 1) 2 3 4))";
assertSExpressionsMatch(parseString("4"), evaluateString(input));
}
@Test
public void condWithNoConditionMatching_ReturnsNil() {
public void condWithNoTrueTest_ReturnsNil() {
String input = "(cond ((= 1 2) T) ((= 1 3) T))";
assertSExpressionsMatch(parseString("nil"), evaluateString(input));