Started refactoring and writing unit tests for DEFUN
This commit is contained in:
parent
37bc303fe8
commit
68510ec1a8
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,38 +1,25 @@
|
|||
package function.builtin;
|
||||
|
||||
import function.LispFunction;
|
||||
import function.*;
|
||||
import sexpression.*;
|
||||
|
||||
/**
|
||||
* <code>CONS</code> 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);
|
||||
|
||||
// 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;
|
||||
|
||||
throw new RuntimeException(errMsg);
|
||||
public CONS() {
|
||||
this.argumentValidator = new ArgumentValidator("CONS");
|
||||
this.argumentValidator.setExactNumberOfArguments(2);
|
||||
}
|
||||
|
||||
// the car of the CONS cell we are going to create
|
||||
SExpression argOne = argList.getCar();
|
||||
public Cons call(Cons argumentList) {
|
||||
argumentValidator.validate(argumentList);
|
||||
|
||||
Cons cdr = (Cons) argList.getCdr();
|
||||
Cons cdr = (Cons) argumentList.getCdr();
|
||||
SExpression firstArgument = argumentList.getCar();
|
||||
SExpression secondArgument = cdr.getCar();
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,34 +5,21 @@ import java.util.HashMap;
|
|||
import function.*;
|
||||
import sexpression.*;
|
||||
|
||||
/**
|
||||
* <code>DEFUN</code> 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);
|
||||
|
||||
// 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;
|
||||
|
||||
throw new RuntimeException(errMsg);
|
||||
public DEFUN() {
|
||||
this.argumentValidator = new ArgumentValidator("DEFUN");
|
||||
this.argumentValidator.setMinimumNumberOfArguments(3);
|
||||
this.argumentValidator.setFirstArgumentExpectedType(Symbol.class);
|
||||
}
|
||||
|
||||
SExpression name = argList.getCar(); // name of the function
|
||||
public SExpression call(Cons argumentList) {
|
||||
argumentValidator.validate(argumentList);
|
||||
|
||||
// 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 <code>false</code>
|
||||
*/
|
||||
public boolean evaluateArguments() {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -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)");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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"));
|
||||
evaluateString("(cdr)");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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 ())");
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue