diff --git a/src/function/ArgumentValidator.java b/src/function/ArgumentValidator.java
index 115b3c2..545af26 100644
--- a/src/function/ArgumentValidator.java
+++ b/src/function/ArgumentValidator.java
@@ -173,22 +173,25 @@ public class ArgumentValidator {
private static final long serialVersionUID = 1L;
private String functionName;
private String argument;
- private Class extends SExpression> expected;
+ private Class extends SExpression> expectedType;
public BadArgumentTypeException(String functionName, SExpression argument,
- Class extends SExpression> expected) {
+ Class extends SExpression> expectedType) {
this.functionName = functionName;
this.argument = argument.toString();
- this.expected = expected;
+ this.expectedType = expectedType;
}
@Override
public String getMessage() {
- DisplayName displayName = expected.getAnnotation(DisplayName.class);
- String expectedType = (displayName == null) ? "unknown" : displayName.value();
-
return MessageFormat.format("{0}: {1} is not the expected type of ''{2}''", functionName, argument,
- expectedType);
+ getExpectedTypeName());
+ }
+
+ private String getExpectedTypeName() {
+ DisplayName displayName = expectedType.getAnnotation(DisplayName.class);
+
+ return (displayName == null) ? "unknown" : displayName.value();
}
}
diff --git a/src/function/UserDefinedFunction.java b/src/function/UserDefinedFunction.java
index b276dde..a9fc27b 100644
--- a/src/function/UserDefinedFunction.java
+++ b/src/function/UserDefinedFunction.java
@@ -38,9 +38,7 @@ public class UserDefinedFunction extends LispFunction {
// bind the values of the arguments to the formal parameter names
for (String param : formalParameters) {
SExpression currentArg = argList.getCar();
-
environment.put(param, currentArg);
-
argList = (Cons) argList.getCdr();
}
diff --git a/src/function/builtin/CONS.java b/src/function/builtin/CONS.java
index 2913115..1703ec8 100644
--- a/src/function/builtin/CONS.java
+++ b/src/function/builtin/CONS.java
@@ -1,38 +1,25 @@
package function.builtin;
-import function.LispFunction;
+import function.*;
import sexpression.*;
-/**
- * CONS
represents the CONS function in Lisp.
- */
public class CONS extends LispFunction {
- // The number of arguments that CONS takes.
- private static final int NUM_ARGS = 2;
+ private ArgumentValidator argumentValidator;
- public Cons call(Cons argList) {
- // retrieve the number of arguments passed to CONS
- int argListLength = LENGTH.getLength(argList);
+ public CONS() {
+ this.argumentValidator = new ArgumentValidator("CONS");
+ this.argumentValidator.setExactNumberOfArguments(2);
+ }
- // make sure we have received the proper number of arguments
- if (argListLength != NUM_ARGS) {
- Cons originalSExpr = new Cons(new Symbol("CONS"), argList);
- String errMsg = "too " + ((argListLength > NUM_ARGS) ? "many" : "few") + " arguments given to CONS: "
- + originalSExpr;
+ public Cons call(Cons argumentList) {
+ argumentValidator.validate(argumentList);
- throw new RuntimeException(errMsg);
- }
+ Cons cdr = (Cons) argumentList.getCdr();
+ SExpression firstArgument = argumentList.getCar();
+ SExpression secondArgument = cdr.getCar();
- // the car of the CONS cell we are going to create
- SExpression argOne = argList.getCar();
-
- Cons cdr = (Cons) argList.getCdr();
-
- // the cdr of the CONS cell we are going to create
- SExpression argTwo = cdr.getCar();
-
- return new Cons(argOne, argTwo);
+ return new Cons(firstArgument, secondArgument);
}
}
diff --git a/src/function/builtin/DEFUN.java b/src/function/builtin/DEFUN.java
index ad167eb..6498b84 100644
--- a/src/function/builtin/DEFUN.java
+++ b/src/function/builtin/DEFUN.java
@@ -5,34 +5,21 @@ import java.util.HashMap;
import function.*;
import sexpression.*;
-/**
- * DEFUN
represents the DEFUN form in Lisp.
- */
public class DEFUN extends LispFunction {
- // The minimum number of arguments that DEFUN takes.
- private static final int MIN_ARGS = 3;
+ private ArgumentValidator argumentValidator;
- public SExpression call(Cons argList) {
- // retrieve the number of arguments passed to DEFUN
- int argListLength = LENGTH.getLength(argList);
+ public DEFUN() {
+ this.argumentValidator = new ArgumentValidator("DEFUN");
+ this.argumentValidator.setMinimumNumberOfArguments(3);
+ this.argumentValidator.setFirstArgumentExpectedType(Symbol.class);
+ }
- // make sure we have received the proper number of arguments
- if (argListLength < MIN_ARGS) {
- Cons originalSExpr = new Cons(new Symbol("DEFUN"), argList);
- String errMsg = "too few arguments given to DEFUN: " + originalSExpr;
+ public SExpression call(Cons argumentList) {
+ argumentValidator.validate(argumentList);
- throw new RuntimeException(errMsg);
- }
-
- SExpression name = argList.getCar(); // name of the function
-
- // make sure the function name is a symbol
- if (!name.symbolp()) {
- throw new RuntimeException("DEFUN: " + name + " is not a symbol");
- }
-
- Cons cdr = (Cons) argList.getCdr();
+ Cons cdr = (Cons) argumentList.getCdr();
+ SExpression name = argumentList.getCar(); // name of the function
SExpression cadr = cdr.getCar();
// make sure the list of arguments (lambda list) is a proper list
@@ -60,11 +47,6 @@ public class DEFUN extends LispFunction {
return name;
}
- /**
- * Determine if the arguments passed to this Lisp function should be evaluated.
- *
- * @return false
- */
public boolean evaluateArguments() {
return false;
}
diff --git a/test/function/builtin/CARTester.java b/test/function/builtin/CARTester.java
index d084e7d..e619370 100644
--- a/test/function/builtin/CARTester.java
+++ b/test/function/builtin/CARTester.java
@@ -36,16 +36,12 @@ public class CARTester {
@Test(expected = TooManyArgumentsException.class)
public void testCarWithTooManyArguments() {
- String input = "(car '(1 2) '(1 2) \"oh\")";
-
- assertSExpressionsMatch(evaluateString(input), parseString("1"));
+ evaluateString("(car '(1 2) '(1 2) \"oh\")");
}
@Test(expected = TooFewArgumentsException.class)
public void testCarWithTooFewArguments() {
- String input = "(car)";
-
- assertSExpressionsMatch(evaluateString(input), parseString("1"));
+ evaluateString("(car)");
}
}
diff --git a/test/function/builtin/CDRTester.java b/test/function/builtin/CDRTester.java
index 7fec962..36b135c 100644
--- a/test/function/builtin/CDRTester.java
+++ b/test/function/builtin/CDRTester.java
@@ -36,16 +36,12 @@ public class CDRTester {
@Test(expected = TooManyArgumentsException.class)
public void testCdrWithTooManyArguments() {
- String input = "(cdr '(1 2) '(1 2) \"oh\")";
-
- assertSExpressionsMatch(evaluateString(input), parseString("1"));
+ evaluateString("(cdr '(1 2) '(1 2) \"oh\")");
}
@Test(expected = TooFewArgumentsException.class)
- public void testCdrWithTooFewArguments() {
- String input = "(cdr)";
-
- assertSExpressionsMatch(evaluateString(input), parseString("1"));
+ public void testCdrWithTooFewArguments() {
+ evaluateString("(cdr)");
}
}
diff --git a/test/function/builtin/CONSTester.java b/test/function/builtin/CONSTester.java
new file mode 100644
index 0000000..3ad96b5
--- /dev/null
+++ b/test/function/builtin/CONSTester.java
@@ -0,0 +1,61 @@
+package function.builtin;
+
+import static testutil.TestUtilities.*;
+
+import org.junit.Test;
+
+import function.ArgumentValidator.*;
+import sexpression.*;
+
+public class CONSTester {
+
+ @Test
+ public void testConsWithNilValues() {
+ String input = "(cons () nil)";
+
+ assertSExpressionsMatch(evaluateString(input), parseString("(())"));
+ }
+
+ @Test
+ public void testConsWithTwoSymbols() {
+ String input = "(cons 'a 'b)";
+
+ assertSExpressionsMatch(evaluateString(input), new Cons(new Symbol("A"), new Symbol("B")));
+ }
+
+ @Test
+ public void testConsWithListAsCdr() {
+ String input = "(cons 1 '(2 3))";
+
+ assertSExpressionsMatch(evaluateString(input), parseString("(1 2 3)"));
+ }
+ @Test
+ public void testConsWithTwoLists() {
+ String input = "(cons '(1 2) '(3 4))";
+
+ assertSExpressionsMatch(evaluateString(input), parseString("((1 2) 3 4)"));
+ }
+
+
+ @Test
+ public void testConsWithList() {
+ String input = "(cons nil '(2 3))";
+
+ assertSExpressionsMatch(evaluateString(input), parseString("(nil 2 3)"));
+ }
+
+ @Test(expected = TooManyArgumentsException.class)
+ public void testConsWithTooManyArguments() {
+ String input = "(cons 1 2 3)";
+
+ evaluateString(input);
+ }
+
+ @Test(expected = TooFewArgumentsException.class)
+ public void testConsWithTooFewArguments() {
+ String input = "(cons 1)";
+
+ evaluateString(input);
+ }
+
+}
diff --git a/test/function/builtin/DEFUNTester.java b/test/function/builtin/DEFUNTester.java
new file mode 100644
index 0000000..1318a45
--- /dev/null
+++ b/test/function/builtin/DEFUNTester.java
@@ -0,0 +1,29 @@
+package function.builtin;
+
+import static testutil.TestUtilities.*;
+
+import org.junit.Test;
+
+import function.ArgumentValidator.*;
+
+public class DEFUNTester {
+
+ @Test
+ public void testDefun() {
+ String input = "(defun f () nil)";
+
+ assertSExpressionsMatch(evaluateString(input), parseString("f"));
+ assertSExpressionsMatch(evaluateString("(f)"), parseString("()"));
+ }
+
+ @Test(expected = BadArgumentTypeException.class)
+ public void testDefunWithNonSymbolName() {
+ evaluateString("(defun 1 () ())");
+ }
+
+ @Test(expected = TooFewArgumentsException.class)
+ public void testApplyWithTooFewArguments() {
+ evaluateString("(defun 1 ())");
+ }
+
+}