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 static final long serialVersionUID = 1L;
|
||||||
private String functionName;
|
private String functionName;
|
||||||
private String argument;
|
private String argument;
|
||||||
private Class<? extends SExpression> expected;
|
private Class<? extends SExpression> expectedType;
|
||||||
|
|
||||||
public BadArgumentTypeException(String functionName, SExpression argument,
|
public BadArgumentTypeException(String functionName, SExpression argument,
|
||||||
Class<? extends SExpression> expected) {
|
Class<? extends SExpression> expectedType) {
|
||||||
this.functionName = functionName;
|
this.functionName = functionName;
|
||||||
this.argument = argument.toString();
|
this.argument = argument.toString();
|
||||||
this.expected = expected;
|
this.expectedType = expectedType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getMessage() {
|
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,
|
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
|
// bind the values of the arguments to the formal parameter names
|
||||||
for (String param : formalParameters) {
|
for (String param : formalParameters) {
|
||||||
SExpression currentArg = argList.getCar();
|
SExpression currentArg = argList.getCar();
|
||||||
|
|
||||||
environment.put(param, currentArg);
|
environment.put(param, currentArg);
|
||||||
|
|
||||||
argList = (Cons) argList.getCdr();
|
argList = (Cons) argList.getCdr();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,38 +1,25 @@
|
||||||
package function.builtin;
|
package function.builtin;
|
||||||
|
|
||||||
import function.LispFunction;
|
import function.*;
|
||||||
import sexpression.*;
|
import sexpression.*;
|
||||||
|
|
||||||
/**
|
|
||||||
* <code>CONS</code> represents the CONS function in Lisp.
|
|
||||||
*/
|
|
||||||
public class CONS extends LispFunction {
|
public class CONS extends LispFunction {
|
||||||
|
|
||||||
// The number of arguments that CONS takes.
|
private ArgumentValidator argumentValidator;
|
||||||
private static final int NUM_ARGS = 2;
|
|
||||||
|
|
||||||
public Cons call(Cons argList) {
|
public CONS() {
|
||||||
// retrieve the number of arguments passed to CONS
|
this.argumentValidator = new ArgumentValidator("CONS");
|
||||||
int argListLength = LENGTH.getLength(argList);
|
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;
|
|
||||||
|
|
||||||
throw new RuntimeException(errMsg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// the car of the CONS cell we are going to create
|
public Cons call(Cons argumentList) {
|
||||||
SExpression argOne = argList.getCar();
|
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
|
return new Cons(firstArgument, secondArgument);
|
||||||
SExpression argTwo = cdr.getCar();
|
|
||||||
|
|
||||||
return new Cons(argOne, argTwo);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,34 +5,21 @@ import java.util.HashMap;
|
||||||
import function.*;
|
import function.*;
|
||||||
import sexpression.*;
|
import sexpression.*;
|
||||||
|
|
||||||
/**
|
|
||||||
* <code>DEFUN</code> represents the DEFUN form in Lisp.
|
|
||||||
*/
|
|
||||||
public class DEFUN extends LispFunction {
|
public class DEFUN extends LispFunction {
|
||||||
|
|
||||||
// The minimum number of arguments that DEFUN takes.
|
private ArgumentValidator argumentValidator;
|
||||||
private static final int MIN_ARGS = 3;
|
|
||||||
|
|
||||||
public SExpression call(Cons argList) {
|
public DEFUN() {
|
||||||
// retrieve the number of arguments passed to DEFUN
|
this.argumentValidator = new ArgumentValidator("DEFUN");
|
||||||
int argListLength = LENGTH.getLength(argList);
|
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;
|
|
||||||
|
|
||||||
throw new RuntimeException(errMsg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SExpression name = argList.getCar(); // name of the function
|
public SExpression call(Cons argumentList) {
|
||||||
|
argumentValidator.validate(argumentList);
|
||||||
|
|
||||||
// make sure the function name is a symbol
|
Cons cdr = (Cons) argumentList.getCdr();
|
||||||
if (!name.symbolp()) {
|
SExpression name = argumentList.getCar(); // name of the function
|
||||||
throw new RuntimeException("DEFUN: " + name + " is not a symbol");
|
|
||||||
}
|
|
||||||
|
|
||||||
Cons cdr = (Cons) argList.getCdr();
|
|
||||||
SExpression cadr = cdr.getCar();
|
SExpression cadr = cdr.getCar();
|
||||||
|
|
||||||
// make sure the list of arguments (lambda list) is a proper list
|
// make sure the list of arguments (lambda list) is a proper list
|
||||||
|
@ -60,11 +47,6 @@ public class DEFUN extends LispFunction {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine if the arguments passed to this Lisp function should be evaluated.
|
|
||||||
*
|
|
||||||
* @return <code>false</code>
|
|
||||||
*/
|
|
||||||
public boolean evaluateArguments() {
|
public boolean evaluateArguments() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,16 +36,12 @@ public class CARTester {
|
||||||
|
|
||||||
@Test(expected = TooManyArgumentsException.class)
|
@Test(expected = TooManyArgumentsException.class)
|
||||||
public void testCarWithTooManyArguments() {
|
public void testCarWithTooManyArguments() {
|
||||||
String input = "(car '(1 2) '(1 2) \"oh\")";
|
evaluateString("(car '(1 2) '(1 2) \"oh\")");
|
||||||
|
|
||||||
assertSExpressionsMatch(evaluateString(input), parseString("1"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = TooFewArgumentsException.class)
|
@Test(expected = TooFewArgumentsException.class)
|
||||||
public void testCarWithTooFewArguments() {
|
public void testCarWithTooFewArguments() {
|
||||||
String input = "(car)";
|
evaluateString("(car)");
|
||||||
|
|
||||||
assertSExpressionsMatch(evaluateString(input), parseString("1"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,16 +36,12 @@ public class CDRTester {
|
||||||
|
|
||||||
@Test(expected = TooManyArgumentsException.class)
|
@Test(expected = TooManyArgumentsException.class)
|
||||||
public void testCdrWithTooManyArguments() {
|
public void testCdrWithTooManyArguments() {
|
||||||
String input = "(cdr '(1 2) '(1 2) \"oh\")";
|
evaluateString("(cdr '(1 2) '(1 2) \"oh\")");
|
||||||
|
|
||||||
assertSExpressionsMatch(evaluateString(input), parseString("1"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = TooFewArgumentsException.class)
|
@Test(expected = TooFewArgumentsException.class)
|
||||||
public void testCdrWithTooFewArguments() {
|
public void testCdrWithTooFewArguments() {
|
||||||
String input = "(cdr)";
|
evaluateString("(cdr)");
|
||||||
|
|
||||||
assertSExpressionsMatch(evaluateString(input), parseString("1"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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