diff --git a/src/function/builtin/EQUAL.java b/src/function/builtin/EQUAL.java index 72ad6a4..5d2d779 100644 --- a/src/function/builtin/EQUAL.java +++ b/src/function/builtin/EQUAL.java @@ -1,48 +1,66 @@ package function.builtin; -import function.LispFunction; +import function.*; import sexpression.*; -/** - * EQUAL represents the EQUAL function in Lisp. - */ public class EQUAL extends LispFunction { - // The number of arguments that EQUAL takes. - private static final int NUM_ARGS = 2; + private ArgumentValidator argumentValidator; - public SExpression call(Cons argList) { - // retrieve the number of arguments passed to EQUAL - int argListLength = LENGTH.getLength(argList); + public EQUAL() { + this.argumentValidator = new ArgumentValidator("EQUAL"); + this.argumentValidator.setExactNumberOfArguments(2); + } - // make sure we have received the proper number of arguments - if (argListLength != NUM_ARGS) { - Cons originalSExpr = new Cons(new Symbol("EQUAL"), argList); - String errMsg = "too " + ((argListLength > NUM_ARGS) ? "many" : "few") + " arguments given to EQUAL: " - + originalSExpr; + public SExpression call(Cons argumentList) { + argumentValidator.validate(argumentList); - throw new RuntimeException(errMsg); - } + return callRecursive(argumentList); + } - SExpression argOne = argList.getCar(); // first argument - Cons cdr = (Cons) argList.getCdr(); - SExpression argTwo = cdr.getCar(); // second argumnet + private SExpression callRecursive(Cons argumentList) { + Cons cdr = (Cons) argumentList.getCdr(); + SExpression firstArgument = argumentList.getCar(); + SExpression secondArgument = cdr.getCar(); - if (argOne.consp() && argTwo.consp()) { - Cons listOne = (Cons) argOne; - Cons listTwo = (Cons) argTwo; - SExpression listOneCar = listOne.getCar(); - SExpression listTwoCar = listTwo.getCar(); - SExpression listOneCdr = listOne.getCdr(); - SExpression listTwoCdr = listTwo.getCdr(); + if (!isListPair(firstArgument, secondArgument)) + return equal(firstArgument, secondArgument); - SExpression carEqual = call(new Cons(listOneCar, LIST.makeList(listTwoCar))); - SExpression cdrEqual = call(new Cons(listOneCdr, LIST.makeList(listTwoCdr))); + Cons listOne = (Cons) firstArgument; + Cons listTwo = (Cons) secondArgument; + SExpression listOneCar = listOne.getCar(); + SExpression listTwoCar = listTwo.getCar(); + SExpression listOneCdr = listOne.getCdr(); + SExpression listTwoCdr = listTwo.getCdr(); - return (((carEqual == Symbol.T) && (cdrEqual == Symbol.T)) ? Symbol.T : Nil.getInstance()); - } + SExpression carEqual = callRecursive(makeArgumentList(listOneCar, listTwoCar)); + SExpression cdrEqual = callRecursive(makeArgumentList(listOneCdr, listTwoCdr)); - return ((argOne.toString().equals(argTwo.toString())) ? Symbol.T : Nil.getInstance()); + return logicalConjunction(carEqual, cdrEqual); + } + + private boolean isListPair(SExpression firstArgument, SExpression secondArgument) { + return firstArgument.consp() && secondArgument.consp(); + } + + private SExpression equal(SExpression firstArgument, SExpression secondArgument) { + return isEqual(firstArgument, secondArgument) ? Symbol.T : Nil.getInstance(); + } + + private boolean isEqual(SExpression firstArgument, SExpression secondArgument) { + return firstArgument.toString().equals(secondArgument.toString()); + } + + private Cons makeArgumentList(SExpression listOneCar, SExpression listTwoCar) { + return new Cons(listOneCar, LIST.makeList(listTwoCar)); + } + + private SExpression logicalConjunction(SExpression carEqual, SExpression cdrEqual) { + return bothAreTrue(carEqual, cdrEqual) ? Symbol.T : Nil.getInstance(); + } + + private boolean bothAreTrue(SExpression carEqual, SExpression cdrEqual) { + return (carEqual == Symbol.T) && (cdrEqual == Symbol.T); } } diff --git a/test/function/builtin/EQUALTester.java b/test/function/builtin/EQUALTester.java index 13e21ce..a49b40f 100644 --- a/test/function/builtin/EQUALTester.java +++ b/test/function/builtin/EQUALTester.java @@ -9,39 +9,62 @@ import function.ArgumentValidator.*; public class EQUALTester { @Test - public void testCarWithNil() { - String input = "(car nil)"; + public void testEqualWithTwoEqualAtoms() { + String input = "(equal 'a 'a)"; - assertSExpressionsMatch(evaluateString(input), parseString("()")); + assertSExpressionsMatch(evaluateString(input), parseString("t")); } @Test - public void testCarWithList() { - String input = "(car '(1 2 3))"; + public void testEqualWithTwoUnequalAtoms() { + String input = "(equal 'a 'b)"; - assertSExpressionsMatch(evaluateString(input), parseString("1")); + assertSExpressionsMatch(evaluateString(input), parseString("nil")); } @Test - public void testNestedCarWithList() { - String input = "(car (car '((1 2) 3)))"; + public void testEqualWithAtomAndList() { + String input = "(equal \"string\" '(m i k e))"; - assertSExpressionsMatch(evaluateString(input), parseString("1")); + assertSExpressionsMatch(evaluateString(input), parseString("nil")); } - @Test(expected = BadArgumentTypeException.class) - public void testCarWithNonList() { - evaluateString("(car 'x)"); + @Test + public void testEqualWithListAndAtom() { + String input = "(equal '(m i k e) \"string\")"; + + assertSExpressionsMatch(evaluateString(input), parseString("nil")); + } + + @Test + public void testEqualWithTwoEqualLists() { + String input = "(equal '(1 2 3) '(1 2 3))"; + + assertSExpressionsMatch(evaluateString(input), parseString("t")); + } + + @Test + public void testEqualWithTwoUnequalLists() { + String input = "(equal '(1 2 3) '(1 3 3))"; + + assertSExpressionsMatch(evaluateString(input), parseString("nil")); + } + + @Test + public void testEqualWithTwoEqualNestedLists() { + String input = "(equal '(1 ((2) 3)) '(1 ((2) 3)))"; + + assertSExpressionsMatch(evaluateString(input), parseString("t")); } @Test(expected = TooManyArgumentsException.class) - public void testCarWithTooManyArguments() { - evaluateString("(car '(1 2) '(1 2) \"oh\")"); + public void testEqualWithTooManyArguments() { + evaluateString("(equal 1 2 3)"); } @Test(expected = TooFewArgumentsException.class) - public void testCarWithTooFewArguments() { - evaluateString("(car)"); + public void testEqualWithTooFewArguments() { + evaluateString("(equal 1)"); } }