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) { private String formatMessage(LispException lispException) {
Severity severity = lispException.getSeverity(); Severity severity = lispException.getSeverity();
String prefix = severity.toDisplayString(); 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); return severity.decorate(message, environment);
} }

View File

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

View File

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

View File

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

View File

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