diff --git a/lisp/problem.lisp b/lisp/problem.lisp
new file mode 100644
index 0000000..693633c
--- /dev/null
+++ b/lisp/problem.lisp
@@ -0,0 +1,3 @@
+(defun problem (n) (cond ((< n 1) nil) (T (cons n (problem (- n 1))))))
+(setf x (problem 20000))
+
diff --git a/src/function/builtin/APPLY.java b/src/function/builtin/APPLY.java
index 33ee0dc..09c1eae 100644
--- a/src/function/builtin/APPLY.java
+++ b/src/function/builtin/APPLY.java
@@ -17,15 +17,15 @@ public class APPLY extends LispFunction {
this.argumentValidator.setTrailingArgumentExpectedType(Cons.class);
}
- public SExpression call(Cons argList) {
- argumentValidator.validate(argList);
+ public SExpression call(Cons argumentList) {
+ argumentValidator.validate(argumentList);
- Cons cdr = (Cons) argList.getCdr();
- SExpression functionName = argList.getCar();
- SExpression argumentList = cdr.getCar();
+ Cons cdr = (Cons) argumentList.getCdr();
+ SExpression functionName = argumentList.getCar();
+ SExpression functionArguments = cdr.getCar();
LispFunction function = EVAL.lookupFunctionOrLambda(functionName);
- return function.call((Cons) argumentList);
+ return function.call((Cons) functionArguments);
}
}
diff --git a/src/function/builtin/CAR.java b/src/function/builtin/CAR.java
index 1ff2d78..1b4a0df 100644
--- a/src/function/builtin/CAR.java
+++ b/src/function/builtin/CAR.java
@@ -1,41 +1,23 @@
package function.builtin;
-import function.LispFunction;
+import function.*;
import sexpression.*;
-/**
- * CAR
represents the CAR function in Lisp.
- */
public class CAR extends LispFunction {
- // The number of arguments that CAR takes.
- private static final int NUM_ARGS = 1;
+ private ArgumentValidator argumentValidator;
- public SExpression call(Cons argList) {
- // retrieve the number of arguments passed to CAR
- int argListLength = LENGTH.getLength(argList);
+ public CAR() {
+ this.argumentValidator = new ArgumentValidator("CAR");
+ this.argumentValidator.setExactNumberOfArguments(1);
+ this.argumentValidator.setEveryArgumentExpectedType(Cons.class);
+ }
- // make sure we have received the proper number of arguments
- if (argListLength != NUM_ARGS) {
- Cons originalSExpr = new Cons(new Symbol("CAR"), argList);
- String errMsg = "too " +
- ((argListLength > NUM_ARGS) ? "many" : "few") +
- " arguments given to CAR: " + originalSExpr;
+ public SExpression call(Cons argumentList) {
+ argumentValidator.validate(argumentList);
+ Cons argument = (Cons) argumentList.getCar();
- throw new RuntimeException(errMsg);
- }
-
- SExpression argCar = argList.getCar();
-
- // make sure that the argument is a list
- if (argCar.listp()) {
- Cons arg = (Cons) argCar;
-
- return arg.getCar();
- }
-
- // the argument is not a list
- throw new RuntimeException("CAR: " + argCar + " is not a list");
+ return argument.getCar();
}
}
diff --git a/src/function/builtin/CDR.java b/src/function/builtin/CDR.java
index 8262646..3fcd578 100644
--- a/src/function/builtin/CDR.java
+++ b/src/function/builtin/CDR.java
@@ -1,41 +1,23 @@
package function.builtin;
-import function.LispFunction;
+import function.*;
import sexpression.*;
-/**
- * CDR
represents the CDR function in Lisp.
- */
public class CDR extends LispFunction {
- // The number of arguments that CDR takes.
- private static final int NUM_ARGS = 1;
+ private ArgumentValidator argumentValidator;
- public SExpression call(Cons argList) {
- // retrieve the number of arguments passed to CDR
- int argListLength = LENGTH.getLength(argList);
+ public CDR() {
+ this.argumentValidator = new ArgumentValidator("CDR");
+ this.argumentValidator.setExactNumberOfArguments(1);
+ this.argumentValidator.setEveryArgumentExpectedType(Cons.class);
+ }
- // make sure we have received the proper number of arguments
- if (argListLength != NUM_ARGS) {
- Cons originalSExpr = new Cons(new Symbol("CDR"), argList);
- String errMsg = "too " +
- ((argListLength > NUM_ARGS) ? "many" : "few") +
- " arguments given to CDR: " + originalSExpr;
+ public SExpression call(Cons argumentList) {
+ argumentValidator.validate(argumentList);
+ Cons argument = (Cons) argumentList.getCar();
- throw new RuntimeException(errMsg);
- }
-
- SExpression argCar = argList.getCar();
-
- // make sure that the argument is a list
- if (argCar.listp()) {
- Cons arg = (Cons) argCar;
-
- return arg.getCdr();
- }
-
- // the argument is not a list
- throw new RuntimeException("CDR: " + argCar + " is not a list");
+ return argument.getCdr();
}
}
diff --git a/src/function/builtin/COND.java b/src/function/builtin/COND.java
index 28f5dee..7f7da02 100644
--- a/src/function/builtin/COND.java
+++ b/src/function/builtin/COND.java
@@ -3,9 +3,6 @@ package function.builtin;
import function.LispFunction;
import sexpression.*;
-/**
- * COND
represents the COND form in Lisp.
- */
public class COND extends LispFunction {
public SExpression call(Cons argList) {
@@ -53,11 +50,6 @@ public class COND extends LispFunction {
throw new RuntimeException("COND: clause " + argCar + " should be a list");
}
- /**
- * Determine if the arguments passed to this Lisp function should be evaluated.
- *
- * @return false
- */
public boolean evaluateArguments() {
return false;
}
diff --git a/test/function/ArgumentValidatorTester.java b/test/function/ArgumentValidatorTester.java
index 6beba37..8a14947 100644
--- a/test/function/ArgumentValidatorTester.java
+++ b/test/function/ArgumentValidatorTester.java
@@ -176,6 +176,13 @@ public class ArgumentValidatorTester {
validator.validate(argumentList);
}
+ @Test(expected = DottedArgumentListException.class)
+ public void givenLargeDottedArgumentList_ThrowsException() {
+ Cons argumentList = new Cons(Symbol.T, new Cons(Symbol.T, Symbol.T));
+
+ validator.validate(argumentList);
+ }
+
@Test
public void dottedArgumentListException_HasMessageText() {
DottedArgumentListException e = new DottedArgumentListException("TEST", Nil.getUniqueInstance());
diff --git a/test/function/builtin/CARTester.java b/test/function/builtin/CARTester.java
new file mode 100644
index 0000000..d084e7d
--- /dev/null
+++ b/test/function/builtin/CARTester.java
@@ -0,0 +1,51 @@
+package function.builtin;
+
+import static testutil.TestUtilities.*;
+
+import org.junit.Test;
+
+import function.ArgumentValidator.*;
+
+public class CARTester {
+
+ @Test
+ public void testCarWithNil() {
+ String input = "(car nil)";
+
+ assertSExpressionsMatch(evaluateString(input), parseString("()"));
+ }
+
+ @Test
+ public void testCarWithList() {
+ String input = "(car '(1 2 3))";
+
+ assertSExpressionsMatch(evaluateString(input), parseString("1"));
+ }
+
+ @Test
+ public void testNestedCarWithList() {
+ String input = "(car (car '((1 2) 3)))";
+
+ assertSExpressionsMatch(evaluateString(input), parseString("1"));
+ }
+
+ @Test(expected = BadArgumentTypeException.class)
+ public void testCarWithNonList() {
+ evaluateString("(car 'x)");
+ }
+
+ @Test(expected = TooManyArgumentsException.class)
+ public void testCarWithTooManyArguments() {
+ String input = "(car '(1 2) '(1 2) \"oh\")";
+
+ assertSExpressionsMatch(evaluateString(input), parseString("1"));
+ }
+
+ @Test(expected = TooFewArgumentsException.class)
+ public void testCarWithTooFewArguments() {
+ String input = "(car)";
+
+ assertSExpressionsMatch(evaluateString(input), parseString("1"));
+ }
+
+}
diff --git a/test/function/builtin/CDRTester.java b/test/function/builtin/CDRTester.java
new file mode 100644
index 0000000..7fec962
--- /dev/null
+++ b/test/function/builtin/CDRTester.java
@@ -0,0 +1,51 @@
+package function.builtin;
+
+import static testutil.TestUtilities.*;
+
+import org.junit.Test;
+
+import function.ArgumentValidator.*;
+
+public class CDRTester {
+
+ @Test
+ public void testCdrWithNil() {
+ String input = "(cdr nil)";
+
+ assertSExpressionsMatch(evaluateString(input), parseString("()"));
+ }
+
+ @Test
+ public void testCdrWithList() {
+ String input = "(cdr '(1 2 3))";
+
+ assertSExpressionsMatch(evaluateString(input), parseString("(2 3)"));
+ }
+
+ @Test
+ public void testNestedCdrWithList() {
+ String input = "(cdr (cdr '(1 2 3)))";
+
+ assertSExpressionsMatch(evaluateString(input), parseString("(3)"));
+ }
+
+ @Test(expected = BadArgumentTypeException.class)
+ public void testCdrWithNonList() {
+ evaluateString("(cdr 'x)");
+ }
+
+ @Test(expected = TooManyArgumentsException.class)
+ public void testCdrWithTooManyArguments() {
+ String input = "(cdr '(1 2) '(1 2) \"oh\")";
+
+ assertSExpressionsMatch(evaluateString(input), parseString("1"));
+ }
+
+ @Test(expected = TooFewArgumentsException.class)
+ public void testCdrWithTooFewArguments() {
+ String input = "(cdr)";
+
+ assertSExpressionsMatch(evaluateString(input), parseString("1"));
+ }
+
+}