From 3cb9d896165bfab997b1c9057319791bba58264e Mon Sep 17 00:00:00 2001 From: Mike Cifelli Date: Wed, 4 Jan 2017 13:57:16 -0500 Subject: [PATCH] Refactored more code and added unit tests for the built in functions --- src/function/builtin/FUNCALL.java | 21 ++++----- src/function/builtin/GREATERP.java | 56 ++++++++++------------- test/function/builtin/FUNCALLTester.java | 32 +++++++++++++ test/function/builtin/GREATERPTester.java | 49 ++++++++++++++++++++ 4 files changed, 115 insertions(+), 43 deletions(-) create mode 100644 test/function/builtin/FUNCALLTester.java create mode 100644 test/function/builtin/GREATERPTester.java diff --git a/src/function/builtin/FUNCALL.java b/src/function/builtin/FUNCALL.java index 3a68677..84811cd 100644 --- a/src/function/builtin/FUNCALL.java +++ b/src/function/builtin/FUNCALL.java @@ -1,23 +1,20 @@ package function.builtin; -import function.LispFunction; +import function.*; import sexpression.*; -/** - * FUNCALL represents the FUNCALL function in Lisp. - */ public class FUNCALL extends LispFunction { - public SExpression call(Cons argList) { - // make sure we have received at least one argument - if (argList.nullp()) { - Cons originalSExpr = new Cons(new Symbol("FUNCALL"), argList); + private ArgumentValidator argumentValidator; - throw new RuntimeException("too few arguments given to FUNCALL: " + originalSExpr); - } + public FUNCALL() { + this.argumentValidator = new ArgumentValidator("FUNCALL"); + this.argumentValidator.setMinimumNumberOfArguments(1); + } - SExpression cdr = argList.getCdr(); - Cons applyArgs = new Cons(argList.getCar(), LIST.makeList(cdr)); + public SExpression call(Cons argumentList) { + argumentValidator.validate(argumentList); + Cons applyArgs = new Cons(argumentList.getCar(), LIST.makeList(argumentList.getCdr())); return APPLY.apply(applyArgs); } diff --git a/src/function/builtin/GREATERP.java b/src/function/builtin/GREATERP.java index a4ed18a..974107f 100644 --- a/src/function/builtin/GREATERP.java +++ b/src/function/builtin/GREATERP.java @@ -1,49 +1,43 @@ package function.builtin; -import function.LispFunction; +import function.*; import sexpression.*; -/** - * GREATERP represents the '>' function in Lisp. - */ public class GREATERP extends LispFunction { - public SExpression call(Cons argList) { - // make sure we have received at least one argument - if (argList.nullp()) { - Cons originalSExpr = new Cons(new Symbol(">"), argList); + private ArgumentValidator argumentValidator; - throw new RuntimeException("too few arguments given to >: " + originalSExpr); - } + public GREATERP() { + this.argumentValidator = new ArgumentValidator("GREATERP"); + this.argumentValidator.setMinimumNumberOfArguments(2); + this.argumentValidator.setEveryArgumentExpectedType(LispNumber.class); + } - SExpression firstArg = argList.getCar(); - Cons argRest = (Cons) argList.getCdr(); + public SExpression call(Cons argumentList) { + argumentValidator.validate(argumentList); - // make sure that the first argument is a number - if (firstArg.numberp()) { - LispNumber num1 = (LispNumber) firstArg; + return callTailRecursive(argumentList); + } - if (argRest.nullp()) { - return Symbol.T; - } + private SExpression callTailRecursive(Cons argumentList) { + Cons remainingArguments = (Cons) argumentList.getCdr(); - SExpression secondArg = argRest.getCar(); + if (remainingArguments.nullp()) + return Symbol.T; - // make sure that the second argument is a number as well - if (secondArg.numberp()) { - LispNumber num2 = (LispNumber) secondArg; + SExpression firstArgument = argumentList.getCar(); + SExpression secondArgument = remainingArguments.getCar(); + LispNumber number1 = (LispNumber) firstArgument; + LispNumber number2 = (LispNumber) secondArgument; - if (num1.getValue().compareTo(num2.getValue()) > 0) { - return call(argRest); - } + if (!isFirstGreater(number1, number2)) + return Nil.getInstance(); - return Nil.getInstance(); - } + return callTailRecursive(remainingArguments); + } - throw new RuntimeException(">: " + secondArg + " is not a number"); - } - - throw new RuntimeException(">: " + firstArg + " is not a number"); + private boolean isFirstGreater(LispNumber number1, LispNumber number2) { + return number1.getValue().compareTo(number2.getValue()) > 0; } } diff --git a/test/function/builtin/FUNCALLTester.java b/test/function/builtin/FUNCALLTester.java new file mode 100644 index 0000000..71d4e06 --- /dev/null +++ b/test/function/builtin/FUNCALLTester.java @@ -0,0 +1,32 @@ +package function.builtin; + +import static testutil.TestUtilities.*; + +import org.junit.Test; + +import function.ArgumentValidator.TooFewArgumentsException; + +public class FUNCALLTester { + + @Test + public void testFuncallWithNumbers() { + String input = "(funcall '+ 1 2 3)"; + + assertSExpressionsMatch(evaluateString(input), parseString("6")); + } + + @Test + public void testFuncallWithUserDefinedFunction() { + String defineUserFunction = "(defun x (n m) (+ n m))"; + String input = "(funcall 'x 2 30)"; + + evaluateString(defineUserFunction); + assertSExpressionsMatch(evaluateString(input), parseString("32")); + } + + @Test(expected = TooFewArgumentsException.class) + public void testFuncallWithTooFewArguments() { + evaluateString("(funcall)"); + } + +} diff --git a/test/function/builtin/GREATERPTester.java b/test/function/builtin/GREATERPTester.java new file mode 100644 index 0000000..9de0446 --- /dev/null +++ b/test/function/builtin/GREATERPTester.java @@ -0,0 +1,49 @@ +package function.builtin; + +import static testutil.TestUtilities.*; + +import org.junit.Test; + +import function.ArgumentValidator.*; + +public class GREATERPTester { + + @Test + public void testGreaterpWithTwoNumbers_ReturnsNil() { + String input = "(> 1 2)"; + + assertSExpressionsMatch(evaluateString(input), parseString("nil")); + } + + @Test + public void testGreaterpWithTwoNumbers_ReturnsT() { + String input = "(> 3 2)"; + + assertSExpressionsMatch(evaluateString(input), parseString("t")); + } + + @Test + public void testGreaterpWithManyNumbers_ReturnsNil() { + String input = "(> 4 3 2 5 1)"; + + assertSExpressionsMatch(evaluateString(input), parseString("nil")); + } + + @Test + public void testGreaterpWithManyNumbers_ReturnsT() { + String input = "(> 4 3 2 1 0)"; + + assertSExpressionsMatch(evaluateString(input), parseString("t")); + } + + @Test(expected = BadArgumentTypeException.class) + public void testGreaterpWithNonNumbers() { + evaluateString("(> 'x 'x)"); + } + + @Test(expected = TooFewArgumentsException.class) + public void testGreaterpWithTooFewArguments() { + evaluateString("(> 1)"); + } + +}