Added more unit tests and refactored some built in functions

This commit is contained in:
Mike Cifelli 2016-12-29 13:32:45 -05:00
parent 4b0c4b44a7
commit d0da7813bd
26 changed files with 383 additions and 156 deletions

View File

@ -16,7 +16,7 @@ public class ATOM extends LispFunction {
argumentValidator.validate(argumentList); argumentValidator.validate(argumentList);
SExpression argument = argumentList.getCar(); SExpression argument = argumentList.getCar();
return argument.atomp() ? Symbol.T : Nil.getUniqueInstance(); return argument.atomp() ? Symbol.T : Nil.getInstance();
} }
} }

View File

@ -21,7 +21,7 @@ public class COND extends LispFunction {
private SExpression callTailRecursive(Cons argumentList) { private SExpression callTailRecursive(Cons argumentList) {
if (argumentList.nullp()) if (argumentList.nullp())
return Nil.getUniqueInstance(); return Nil.getInstance();
Cons clause = (Cons) argumentList.getCar(); Cons clause = (Cons) argumentList.getCar();
Cons remainingClauses = (Cons) argumentList.getCdr(); Cons remainingClauses = (Cons) argumentList.getCdr();
@ -34,7 +34,7 @@ public class COND extends LispFunction {
} }
private boolean isTestSuccessful(SExpression test) { private boolean isTestSuccessful(SExpression test) {
return test != Nil.getUniqueInstance(); return test != Nil.getInstance();
} }
private SExpression evaluateResult(Cons clause, SExpression test) { private SExpression evaluateResult(Cons clause, SExpression test) {

View File

@ -2,54 +2,50 @@ package function.builtin;
import java.math.BigInteger; import java.math.BigInteger;
import function.LispFunction; import function.*;
import sexpression.*; import sexpression.*;
/**
* <code>DIVIDE</code> represents the '/' function in Lisp.
*/
public class DIVIDE extends LispFunction { public class DIVIDE extends LispFunction {
public SExpression call(Cons argList) { private ArgumentValidator argumentValidator;
// make sure we have received at least one argument
if (argList.nullp()) {
Cons originalSExpr = new Cons(new Symbol("/"), argList);
throw new RuntimeException("too few arguments given to /: " + originalSExpr); public DIVIDE() {
this.argumentValidator = new ArgumentValidator("/");
this.argumentValidator.setMinimumNumberOfArguments(1);
this.argumentValidator.setEveryArgumentExpectedType(LispNumber.class);
} }
SExpression argFirst = argList.getCar(); public SExpression call(Cons argumentList) {
Cons argRest = (Cons) argList.getCdr(); argumentValidator.validate(argumentList);
// make sure that the first argument is a number return callTailRecursive(argumentList);
if (argFirst.numberp()) {
LispNumber num1 = (LispNumber) argFirst;
if (argRest.nullp()) {
// there is only one argument, so return the multiplicative
// inverse of the number
return new LispNumber(BigInteger.ONE.divide(num1.getValue()));
} }
SExpression argSecond = argRest.getCar(); private SExpression callTailRecursive(Cons argumentList) {
Cons remainingArguments = (Cons) argumentList.getCdr();
SExpression firstArgument = argumentList.getCar();
LispNumber number1 = (LispNumber) firstArgument;
// make sure that the next argument is a number as well if (remainingArguments.nullp())
if (argSecond.numberp()) { return getReciprocal(number1);
LispNumber num2 = (LispNumber) argSecond;
LispNumber quotient = new LispNumber(num1.getValue().divide(num2.getValue()));
SExpression argCddr = argRest.getCdr();
if (argCddr.consp()) { SExpression secondArgument = remainingArguments.getCar();
return call(new Cons(quotient, argCddr)); LispNumber number2 = (LispNumber) secondArgument;
} LispNumber quotient = divide(number1, number2);
SExpression remainingNumbers = remainingArguments.getCdr();
if (remainingNumbers.nullp())
return quotient; return quotient;
return callTailRecursive(new Cons(quotient, remainingNumbers));
} }
throw new RuntimeException("/: " + argSecond + " is not a number"); private LispNumber getReciprocal(LispNumber number1) {
return new LispNumber(BigInteger.ONE.divide(number1.getValue()));
} }
throw new RuntimeException("/: " + argFirst + " is not a number"); private LispNumber divide(LispNumber number1, LispNumber number2) {
return new LispNumber(number1.getValue().divide(number2.getValue()));
} }
} }

View File

@ -1,38 +1,44 @@
package function.builtin; package function.builtin;
import function.LispFunction; import function.*;
import sexpression.*; import sexpression.*;
/**
* <code>EQ</code> represents the EQ function in Lisp.
*/
public class EQ extends LispFunction { public class EQ extends LispFunction {
// The number of arguments that EQ takes. private ArgumentValidator argumentValidator;
private static final int NUM_ARGS = 2;
public SExpression call(Cons argList) { public EQ() {
// retrieve the number of arguments passed to EQ this.argumentValidator = new ArgumentValidator("EQ");
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("EQ"), argList);
String errMsg = "too " + ((argListLength > NUM_ARGS) ? "many" : "few") + " arguments given to EQ: "
+ originalSExpr;
throw new RuntimeException(errMsg);
} }
SExpression argOne = argList.getCar(); // first argument public SExpression call(Cons argumentList) {
Cons cdr = (Cons) argList.getCdr(); argumentValidator.validate(argumentList);
SExpression argTwo = cdr.getCar(); // second argumnet
if (argOne.atomp() && argTwo.atomp()) { Cons cdr = (Cons) argumentList.getCdr();
return ((argOne.toString().equals(argTwo.toString())) ? Symbol.T : Nil.getUniqueInstance()); SExpression firstArgument = argumentList.getCar();
SExpression secondArgument = cdr.getCar();
return eq(firstArgument, secondArgument);
} }
return ((argOne == argTwo) ? Symbol.T : Nil.getUniqueInstance()); private SExpression eq(SExpression firstArgument, SExpression secondArgument) {
if (isAtomPair(firstArgument, secondArgument))
return atomEq(firstArgument, secondArgument);
return listEq(firstArgument, secondArgument);
}
private boolean isAtomPair(SExpression firstArgument, SExpression secondArgument) {
return firstArgument.atomp() && secondArgument.atomp();
}
private SExpression atomEq(SExpression firstArgument, SExpression secondArgument) {
return (firstArgument.toString().equals(secondArgument.toString())) ? Symbol.T : Nil.getInstance();
}
private SExpression listEq(SExpression firstArgument, SExpression secondArgument) {
return (firstArgument == secondArgument) ? Symbol.T : Nil.getInstance();
} }
} }

View File

@ -39,10 +39,10 @@ public class EQUAL extends LispFunction {
SExpression carEqual = call(new Cons(listOneCar, LIST.makeList(listTwoCar))); SExpression carEqual = call(new Cons(listOneCar, LIST.makeList(listTwoCar)));
SExpression cdrEqual = call(new Cons(listOneCdr, LIST.makeList(listTwoCdr))); SExpression cdrEqual = call(new Cons(listOneCdr, LIST.makeList(listTwoCdr)));
return (((carEqual == Symbol.T) && (cdrEqual == Symbol.T)) ? Symbol.T : Nil.getUniqueInstance()); return (((carEqual == Symbol.T) && (cdrEqual == Symbol.T)) ? Symbol.T : Nil.getInstance());
} }
return ((argOne.toString().equals(argTwo.toString())) ? Symbol.T : Nil.getUniqueInstance()); return ((argOne.toString().equals(argTwo.toString())) ? Symbol.T : Nil.getInstance());
} }
} }

View File

@ -1,49 +1,43 @@
package function.builtin; package function.builtin;
import function.LispFunction; import function.*;
import sexpression.*; import sexpression.*;
/**
* <code>EQUALSP</code> represents the '=' function in Lisp.
*/
public class EQUALSP extends LispFunction { public class EQUALSP extends LispFunction {
public SExpression call(Cons argList) { private ArgumentValidator argumentValidator;
// make sure we have received at least one argument
if (argList.nullp()) {
Cons originalSExpr = new Cons(new Symbol("="), argList);
throw new RuntimeException("too few arguments given to =: " + originalSExpr); public EQUALSP() {
this.argumentValidator = new ArgumentValidator("=");
this.argumentValidator.setMinimumNumberOfArguments(1);
this.argumentValidator.setEveryArgumentExpectedType(LispNumber.class);
} }
SExpression firstArg = argList.getCar(); public SExpression call(Cons argumentList) {
Cons argRest = (Cons) argList.getCdr(); argumentValidator.validate(argumentList);
// make sure that the first argument is a number return callTailRecursive(argumentList);
if (firstArg.numberp()) { }
LispNumber num1 = (LispNumber) firstArg;
if (argRest.nullp()) { private SExpression callTailRecursive(Cons argumentList) {
Cons remainingArguments = (Cons) argumentList.getCdr();
if (remainingArguments.nullp())
return Symbol.T; return Symbol.T;
SExpression firstArgument = argumentList.getCar();
LispNumber number1 = (LispNumber) firstArgument;
SExpression secondArgument = remainingArguments.getCar();
LispNumber number2 = (LispNumber) secondArgument;
if (!isEqual(number1, number2))
return Nil.getInstance();
return callTailRecursive(remainingArguments);
} }
SExpression secondArg = argRest.getCar(); private boolean isEqual(LispNumber number1, LispNumber number2) {
return number1.getValue().equals(number2.getValue());
// make sure that the second argument is a number as well
if (secondArg.numberp()) {
LispNumber num2 = (LispNumber) secondArg;
if (num1.getValue().equals(num2.getValue())) {
return call(argRest);
}
return Nil.getUniqueInstance();
}
throw new RuntimeException("=: " + secondArg + " is not a number");
}
throw new RuntimeException("=: " + firstArg + " is not a number");
} }
} }

View File

@ -73,7 +73,7 @@ public class EVAL extends LispFunction {
public static SExpression lookupSymbol(String symbolName) { public static SExpression lookupSymbol(String symbolName) {
if (symbolName.equals("NIL")) { if (symbolName.equals("NIL")) {
return Nil.getUniqueInstance(); return Nil.getInstance();
} else if (symbolName.equals("T")) { } else if (symbolName.equals("T")) {
return Symbol.T; return Symbol.T;
} else if (symbolName.startsWith(":")) { } else if (symbolName.startsWith(":")) {
@ -173,7 +173,7 @@ public class EVAL extends LispFunction {
private Cons evaluateArgList(Cons arguments) { private Cons evaluateArgList(Cons arguments) {
if (arguments.nullp()) { if (arguments.nullp()) {
return Nil.getUniqueInstance(); return Nil.getInstance();
} }
SExpression car = eval(arguments.getCar()); SExpression car = eval(arguments.getCar());
@ -185,7 +185,7 @@ public class EVAL extends LispFunction {
// remove any parameters found after a dot (put here in case the check // remove any parameters found after a dot (put here in case the check
// for a dotted parameter list is not done prior to this call) // for a dotted parameter list is not done prior to this call)
return new Cons(car, Nil.getUniqueInstance()); return new Cons(car, Nil.getInstance());
} }
} }

View File

@ -37,7 +37,7 @@ public class GREATERP extends LispFunction {
return call(argRest); return call(argRest);
} }
return Nil.getUniqueInstance(); return Nil.getInstance();
} }
throw new RuntimeException(">: " + secondArg + " is not a number"); throw new RuntimeException(">: " + secondArg + " is not a number");

View File

@ -37,7 +37,7 @@ public class LESSP extends LispFunction {
return call(argRest); return call(argRest);
} }
return Nil.getUniqueInstance(); return Nil.getInstance();
} }
throw new RuntimeException("<: " + secondArg + " is not a number"); throw new RuntimeException("<: " + secondArg + " is not a number");

View File

@ -25,7 +25,7 @@ public class LET extends LispFunction {
addVariablesToTable(environment, car); addVariablesToTable(environment, car);
SETF.setEnvironment(environment); SETF.setEnvironment(environment);
SExpression retval = Nil.getUniqueInstance(); SExpression retval = Nil.getInstance();
// evaluate all S-expression in the body // evaluate all S-expression in the body
while (cdr.consp()) { while (cdr.consp()) {

View File

@ -17,13 +17,13 @@ public class LIST extends LispFunction {
* a list with <code>sexpr</code> as the car and NIL as the cdr. * a list with <code>sexpr</code> as the car and NIL as the cdr.
*/ */
public static Cons makeList(SExpression sexpr) { public static Cons makeList(SExpression sexpr) {
return new Cons(sexpr, Nil.getUniqueInstance()); return new Cons(sexpr, Nil.getInstance());
} }
public Cons call(Cons argList) { public Cons call(Cons argList) {
if (argList.nullp()) { if (argList.nullp()) {
// return NIL if there were no arguments passed to LIST // return NIL if there were no arguments passed to LIST
return Nil.getUniqueInstance(); return Nil.getInstance();
} }
SExpression argCar = argList.getCar(); SExpression argCar = argList.getCar();

View File

@ -26,7 +26,7 @@ public class LISTP extends LispFunction {
SExpression arg = argList.getCar(); SExpression arg = argList.getCar();
return (arg.listp() ? Symbol.T : Nil.getUniqueInstance()); return (arg.listp() ? Symbol.T : Nil.getInstance());
} }
} }

View File

@ -58,7 +58,7 @@ public class LOAD extends LispFunction {
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
System.out.println("LOAD: could not open " + fileName); System.out.println("LOAD: could not open " + fileName);
return Nil.getUniqueInstance(); return Nil.getInstance();
} }
// attempt to evaluate all the S-expressions contained in the file // attempt to evaluate all the S-expressions contained in the file
@ -70,7 +70,7 @@ public class LOAD extends LispFunction {
} catch (RuntimeException e) { } catch (RuntimeException e) {
System.out.println("LOAD: " + e.getMessage()); System.out.println("LOAD: " + e.getMessage());
return Nil.getUniqueInstance(); return Nil.getInstance();
} }
} }

View File

@ -26,7 +26,7 @@ public class NULL extends LispFunction {
SExpression arg = argList.getCar(); SExpression arg = argList.getCar();
return (arg.nullp() ? Symbol.T : Nil.getUniqueInstance()); return (arg.nullp() ? Symbol.T : Nil.getInstance());
} }
} }

View File

@ -5,7 +5,7 @@ public class Nil extends Cons {
private static Nil uniqueInstance = new Nil(); private static Nil uniqueInstance = new Nil();
public static Nil getUniqueInstance() { public static Nil getInstance() {
return uniqueInstance; return uniqueInstance;
} }
@ -33,14 +33,12 @@ public class Nil extends Cons {
} }
/** /**
* Set the car of this CONS cell to the specified value. This method does nothing (the car of * The car of NIL can not be changed.
* NIL can not be changed).
*/ */
public void setCar(SExpression newCar) {} public void setCar(SExpression newCar) {}
/** /**
* Set the cdr of this CONS cell to the specified value. This method does nothing (the cdr of * The cdr of NIL can not be changed.
* NIL can not be changed).
*/ */
public void setCdr(SExpression newCdr) {} public void setCdr(SExpression newCdr) {}

View File

@ -16,7 +16,7 @@ public class QuoteMark extends Token {
Token nextToken = getNextToken.get(); Token nextToken = getNextToken.get();
SExpression argument = nextToken.parseSExpression(getNextToken); SExpression argument = nextToken.parseSExpression(getNextToken);
return new Cons(Symbol.createQuote(), new Cons(argument, Nil.getUniqueInstance())); return new Cons(Symbol.createQuote(), new Cons(argument, Nil.getInstance()));
} }
} }

View File

@ -19,7 +19,7 @@ public class RightParenthesis extends Token {
@Override @Override
public SExpression parseSExpressionTail(Supplier<Token> getNextToken) { public SExpression parseSExpressionTail(Supplier<Token> getNextToken) {
return Nil.getUniqueInstance(); return Nil.getInstance();
} }
public static class StartsWithRightParenthesisException extends LineColumnException { public static class StartsWithRightParenthesisException extends LineColumnException {

View File

@ -13,10 +13,10 @@ public class ArgumentValidatorTester {
private ArgumentValidator validator; private ArgumentValidator validator;
private Cons makeArgumentListOfSize(int size) { private Cons makeArgumentListOfSize(int size) {
Cons argumentList = Nil.getUniqueInstance(); Cons argumentList = Nil.getInstance();
for (int i = 0; i < size; i++) for (int i = 0; i < size; i++)
argumentList = new Cons(Nil.getUniqueInstance(), argumentList); argumentList = new Cons(Nil.getInstance(), argumentList);
return argumentList; return argumentList;
} }
@ -73,14 +73,14 @@ public class ArgumentValidatorTester {
@Test @Test
public void tooManyArgumentsException_HasCorrectSeverity() { public void tooManyArgumentsException_HasCorrectSeverity() {
TooManyArgumentsException e = new TooManyArgumentsException("TEST", Nil.getUniqueInstance()); TooManyArgumentsException e = new TooManyArgumentsException("TEST", Nil.getInstance());
assertTrue(e.getSeverity() < ErrorManager.CRITICAL_LEVEL); assertTrue(e.getSeverity() < ErrorManager.CRITICAL_LEVEL);
} }
@Test @Test
public void tooManyArgumentsException_HasMessageText() { public void tooManyArgumentsException_HasMessageText() {
TooManyArgumentsException e = new TooManyArgumentsException("TEST", Nil.getUniqueInstance()); TooManyArgumentsException e = new TooManyArgumentsException("TEST", Nil.getInstance());
assertNotNull(e.getMessage()); assertNotNull(e.getMessage());
assertTrue(e.getMessage().length() > 0); assertTrue(e.getMessage().length() > 0);
@ -88,14 +88,14 @@ public class ArgumentValidatorTester {
@Test @Test
public void tooFewArgumentsException_HasCorrectSeverity() { public void tooFewArgumentsException_HasCorrectSeverity() {
TooFewArgumentsException e = new TooFewArgumentsException("TEST", Nil.getUniqueInstance()); TooFewArgumentsException e = new TooFewArgumentsException("TEST", Nil.getInstance());
assertTrue(e.getSeverity() < ErrorManager.CRITICAL_LEVEL); assertTrue(e.getSeverity() < ErrorManager.CRITICAL_LEVEL);
} }
@Test @Test
public void tooFewArgumentsException_HasMessageText() { public void tooFewArgumentsException_HasMessageText() {
TooFewArgumentsException e = new TooFewArgumentsException("TEST", Nil.getUniqueInstance()); TooFewArgumentsException e = new TooFewArgumentsException("TEST", Nil.getInstance());
assertNotNull(e.getMessage()); assertNotNull(e.getMessage());
assertTrue(e.getMessage().length() > 0); assertTrue(e.getMessage().length() > 0);
@ -103,14 +103,14 @@ public class ArgumentValidatorTester {
@Test @Test
public void BadArgumentTypeException_HasCorrectSeverity() { public void BadArgumentTypeException_HasCorrectSeverity() {
BadArgumentTypeException e = new BadArgumentTypeException("TEST", Nil.getUniqueInstance(), SExpression.class); BadArgumentTypeException e = new BadArgumentTypeException("TEST", Nil.getInstance(), SExpression.class);
assertTrue(e.getSeverity() < ErrorManager.CRITICAL_LEVEL); assertTrue(e.getSeverity() < ErrorManager.CRITICAL_LEVEL);
} }
@Test @Test
public void BadArgumentTypeException_HasMessageText() { public void BadArgumentTypeException_HasMessageText() {
BadArgumentTypeException e = new BadArgumentTypeException("TEST", Nil.getUniqueInstance(), SExpression.class); BadArgumentTypeException e = new BadArgumentTypeException("TEST", Nil.getInstance(), SExpression.class);
assertNotNull(e.getMessage()); assertNotNull(e.getMessage());
assertTrue(e.getMessage().length() > 0); assertTrue(e.getMessage().length() > 0);
@ -130,7 +130,7 @@ public class ArgumentValidatorTester {
@Test @Test
public void correctFirstAndRestArgumentTypes_DoesNotThrowException() { public void correctFirstAndRestArgumentTypes_DoesNotThrowException() {
Cons argumentList = new Cons(Symbol.T, new Cons(Nil.getUniqueInstance(), Nil.getUniqueInstance())); Cons argumentList = new Cons(Symbol.T, new Cons(Nil.getInstance(), Nil.getInstance()));
validator.setFirstArgumentExpectedType(Symbol.class); validator.setFirstArgumentExpectedType(Symbol.class);
validator.setTrailingArgumentExpectedType(Cons.class); validator.setTrailingArgumentExpectedType(Cons.class);
@ -139,7 +139,7 @@ public class ArgumentValidatorTester {
@Test(expected = BadArgumentTypeException.class) @Test(expected = BadArgumentTypeException.class)
public void badFirstArgumentType_ThrowsException() { public void badFirstArgumentType_ThrowsException() {
Cons argumentList = new Cons(Symbol.T, new Cons(Nil.getUniqueInstance(), Nil.getUniqueInstance())); Cons argumentList = new Cons(Symbol.T, new Cons(Nil.getInstance(), Nil.getInstance()));
validator.setFirstArgumentExpectedType(Cons.class); validator.setFirstArgumentExpectedType(Cons.class);
validator.setTrailingArgumentExpectedType(Cons.class); validator.setTrailingArgumentExpectedType(Cons.class);
@ -148,7 +148,7 @@ public class ArgumentValidatorTester {
@Test(expected = BadArgumentTypeException.class) @Test(expected = BadArgumentTypeException.class)
public void badTrailingArgumentType_ThrowsException() { public void badTrailingArgumentType_ThrowsException() {
Cons argumentList = new Cons(Symbol.T, new Cons(Nil.getUniqueInstance(), Nil.getUniqueInstance())); Cons argumentList = new Cons(Symbol.T, new Cons(Nil.getInstance(), Nil.getInstance()));
validator.setFirstArgumentExpectedType(Symbol.class); validator.setFirstArgumentExpectedType(Symbol.class);
validator.setTrailingArgumentExpectedType(Symbol.class); validator.setTrailingArgumentExpectedType(Symbol.class);
@ -157,7 +157,7 @@ public class ArgumentValidatorTester {
@Test @Test
public void expectedTypeWithNoDisplayName_DoesNotCauseNPE() { public void expectedTypeWithNoDisplayName_DoesNotCauseNPE() {
Cons argumentList = new Cons(Symbol.T, new Cons(Nil.getUniqueInstance(), Nil.getUniqueInstance())); Cons argumentList = new Cons(Symbol.T, new Cons(Nil.getInstance(), Nil.getInstance()));
SExpression withoutDisplayName = new SExpression() {}; SExpression withoutDisplayName = new SExpression() {};
validator.setEveryArgumentExpectedType(withoutDisplayName.getClass()); validator.setEveryArgumentExpectedType(withoutDisplayName.getClass());
@ -186,14 +186,14 @@ public class ArgumentValidatorTester {
@Test @Test
public void DottedArgumentListException_HasCorrectSeverity() { public void DottedArgumentListException_HasCorrectSeverity() {
DottedArgumentListException e = new DottedArgumentListException("TEST", Nil.getUniqueInstance()); DottedArgumentListException e = new DottedArgumentListException("TEST", Nil.getInstance());
assertTrue(e.getSeverity() < ErrorManager.CRITICAL_LEVEL); assertTrue(e.getSeverity() < ErrorManager.CRITICAL_LEVEL);
} }
@Test @Test
public void dottedArgumentListException_HasMessageText() { public void dottedArgumentListException_HasMessageText() {
DottedArgumentListException e = new DottedArgumentListException("TEST", Nil.getUniqueInstance()); DottedArgumentListException e = new DottedArgumentListException("TEST", Nil.getInstance());
assertNotNull(e.getMessage()); assertNotNull(e.getMessage());
assertTrue(e.getMessage().length() > 0); assertTrue(e.getMessage().length() > 0);
@ -202,19 +202,19 @@ public class ArgumentValidatorTester {
@Test(expected = BadArgumentTypeException.class) @Test(expected = BadArgumentTypeException.class)
public void doNotAcceptNil_ThrowsExceptionOnNilArgument() { public void doNotAcceptNil_ThrowsExceptionOnNilArgument() {
validator.doNotAcceptNil(); validator.doNotAcceptNil();
validator.validate(new Cons(Symbol.T, new Cons(Nil.getUniqueInstance(), Nil.getUniqueInstance()))); validator.validate(new Cons(Symbol.T, new Cons(Nil.getInstance(), Nil.getInstance())));
} }
@Test @Test
public void doNotAcceptNil_AllowsEmptyArgumentList() { public void doNotAcceptNil_AllowsEmptyArgumentList() {
validator.doNotAcceptNil(); validator.doNotAcceptNil();
validator.validate(Nil.getUniqueInstance()); validator.validate(Nil.getInstance());
} }
@Test @Test
public void doNotAcceptNil_AllowsProperList() { public void doNotAcceptNil_AllowsProperList() {
validator.doNotAcceptNil(); validator.doNotAcceptNil();
validator.validate(new Cons(Symbol.T, new Cons(Symbol.T, Nil.getUniqueInstance()))); validator.validate(new Cons(Symbol.T, new Cons(Symbol.T, Nil.getInstance())));
} }
} }

View File

@ -13,28 +13,28 @@ public class UserDefinedFunctionTester {
private static final String FUNCTION_NAME = "TEST"; private static final String FUNCTION_NAME = "TEST";
private UserDefinedFunction createNoArgumentFunctionThatReturnsNil() { private UserDefinedFunction createNoArgumentFunctionThatReturnsNil() {
return new UserDefinedFunction(FUNCTION_NAME, Nil.getUniqueInstance(), return new UserDefinedFunction(FUNCTION_NAME, Nil.getInstance(),
new Cons(Nil.getUniqueInstance(), Nil.getUniqueInstance())); new Cons(Nil.getInstance(), Nil.getInstance()));
} }
private UserDefinedFunction createOneArgumentFunctionThatReturnsArgument() { private UserDefinedFunction createOneArgumentFunctionThatReturnsArgument() {
return new UserDefinedFunction(FUNCTION_NAME, new Cons(new Symbol("X"), Nil.getUniqueInstance()), return new UserDefinedFunction(FUNCTION_NAME, new Cons(new Symbol("X"), Nil.getInstance()),
new Cons(new Symbol("X"), Nil.getUniqueInstance())); new Cons(new Symbol("X"), Nil.getInstance()));
} }
@Test @Test
public void testNilFunctionCall() { public void testNilFunctionCall() {
UserDefinedFunction function = createNoArgumentFunctionThatReturnsNil(); UserDefinedFunction function = createNoArgumentFunctionThatReturnsNil();
assertEquals(Nil.getUniqueInstance(), function.call(Nil.getUniqueInstance())); assertEquals(Nil.getInstance(), function.call(Nil.getInstance()));
} }
@Test @Test
public void testNilFunctionToString() { public void testNilFunctionToString() {
UserDefinedFunction function = createNoArgumentFunctionThatReturnsNil(); UserDefinedFunction function = createNoArgumentFunctionThatReturnsNil();
Cons expected = new Cons(new Symbol(FUNCTION_NAME), Cons expected = new Cons(new Symbol(FUNCTION_NAME),
new Cons(Nil.getUniqueInstance(), new Cons(Nil.getInstance(),
new Cons(Nil.getUniqueInstance(), Nil.getUniqueInstance()))); new Cons(Nil.getInstance(), Nil.getInstance())));
assertSExpressionsMatch(expected, function.getLambdaExpression()); assertSExpressionsMatch(expected, function.getLambdaExpression());
} }
@ -43,7 +43,7 @@ public class UserDefinedFunctionTester {
public void oneArgumentFunction_ReturnsCorrectValue() { public void oneArgumentFunction_ReturnsCorrectValue() {
UserDefinedFunction function = createOneArgumentFunctionThatReturnsArgument(); UserDefinedFunction function = createOneArgumentFunctionThatReturnsArgument();
SExpression argument = new LispNumber("23"); SExpression argument = new LispNumber("23");
Cons argumentList = new Cons(argument, Nil.getUniqueInstance()); Cons argumentList = new Cons(argument, Nil.getInstance());
assertSExpressionsMatch(argument, function.call(argumentList)); assertSExpressionsMatch(argument, function.call(argumentList));
} }
@ -52,7 +52,7 @@ public class UserDefinedFunctionTester {
public void oneArgumentFunction_ThrowsExceptionWithTooManyArguments() { public void oneArgumentFunction_ThrowsExceptionWithTooManyArguments() {
UserDefinedFunction function = createOneArgumentFunctionThatReturnsArgument(); UserDefinedFunction function = createOneArgumentFunctionThatReturnsArgument();
SExpression argument = new LispNumber("23"); SExpression argument = new LispNumber("23");
Cons argumentList = new Cons(argument, new Cons(argument, Nil.getUniqueInstance())); Cons argumentList = new Cons(argument, new Cons(argument, Nil.getInstance()));
function.call(argumentList); function.call(argumentList);
} }
@ -61,7 +61,7 @@ public class UserDefinedFunctionTester {
public void oneArgumentFunction_ThrowsExceptionWithTooFewArguments() { public void oneArgumentFunction_ThrowsExceptionWithTooFewArguments() {
UserDefinedFunction function = createOneArgumentFunctionThatReturnsArgument(); UserDefinedFunction function = createOneArgumentFunctionThatReturnsArgument();
function.call(Nil.getUniqueInstance()); function.call(Nil.getInstance());
} }
} }

View File

@ -0,0 +1,63 @@
package function.builtin;
import static testutil.TestUtilities.*;
import org.junit.Test;
import function.ArgumentValidator.*;
public class DIVIDETester {
@Test
public void testDivideWithOne() {
String input = "(/ 1)";
assertSExpressionsMatch(evaluateString(input), parseString("1"));
}
@Test
public void testDivideWithTwo() {
String input = "(/ 2)";
assertSExpressionsMatch(evaluateString(input), parseString("0"));
}
@Test
public void testDivideTwoNumbers() {
String input = "(/ 24 3)";
assertSExpressionsMatch(evaluateString(input), parseString("8"));
}
@Test
public void testDivideSeveralNumbers() {
String input = "(/ 256 2 2 8)";
assertSExpressionsMatch(evaluateString(input), parseString("8"));
}
@Test
public void testDivideTwoNumbersWithRemainder() {
String input = "(/ 9 2)";
assertSExpressionsMatch(evaluateString(input), parseString("4"));
}
@Test
public void testDivideSeveralNumbersWithRemainder() {
String input = "(/ 19 2 5)";
assertSExpressionsMatch(evaluateString(input), parseString("1"));
}
@Test(expected = BadArgumentTypeException.class)
public void testDivideWithNonNumber() {
evaluateString("(/ 'x)");
}
@Test(expected = TooFewArgumentsException.class)
public void testDivideWithTooFewArguments() {
evaluateString("(/)");
}
}

View File

@ -0,0 +1,67 @@
package function.builtin;
import static testutil.TestUtilities.*;
import org.junit.Test;
import function.ArgumentValidator.*;
public class EQTester {
@Test
public void testEqWithEqualAtoms() {
String input = "(eq 1 1)";
assertSExpressionsMatch(evaluateString(input), parseString("t"));
}
@Test
public void testEqWithUnequalAtoms() {
String input = "(eq 1 2)";
assertSExpressionsMatch(evaluateString(input), parseString("nil"));
}
@Test
public void testEqWithAtomAndList() {
String input = "(eq 1 '(2))";
assertSExpressionsMatch(evaluateString(input), parseString("nil"));
}
@Test
public void testEqWithSameList() {
String initializeL1 = "(setf l1 '(1 2 3))";
String initializeL2 = "(setf l2 l1)";
String input = "(eq l1 l2)";
evaluateString(initializeL1);
evaluateString(initializeL2);
assertSExpressionsMatch(evaluateString(input), parseString("t"));
}
@Test
public void testEqWithEqualLists() {
String input = "(eq '(1 2) '(1 2))";
assertSExpressionsMatch(evaluateString(input), parseString("nil"));
}
@Test
public void testEqWithUnequalLists() {
String input = "(eq '(1 2) '(3 4))";
assertSExpressionsMatch(evaluateString(input), parseString("nil"));
}
@Test(expected = TooManyArgumentsException.class)
public void testEqWithTooManyArguments() {
evaluateString("(eq 'one 'two 'three)");
}
@Test(expected = TooFewArgumentsException.class)
public void testEqWithTooFewArguments() {
evaluateString("(eq 'one)");
}
}

View File

@ -0,0 +1,56 @@
package function.builtin;
import static testutil.TestUtilities.*;
import org.junit.Test;
import function.ArgumentValidator.*;
public class EQUALSPTester {
@Test
public void testEqualspWithOneNumber() {
String input = "(= 1)";
assertSExpressionsMatch(evaluateString(input), parseString("t"));
}
@Test
public void testEqualspWithEqualNumbers() {
String input = "(= 1 1)";
assertSExpressionsMatch(evaluateString(input), parseString("t"));
}
@Test
public void testEqualspWithNonEqualNumbers() {
String input = "(= 1 2)";
assertSExpressionsMatch(evaluateString(input), parseString("nil"));
}
@Test
public void testEqualspWithManyEqualNumbers() {
String input = "(= 4 4 4 4 4 4 4 4 4 4)";
assertSExpressionsMatch(evaluateString(input), parseString("t"));
}
@Test
public void testEqualspWithManyNonEqualNumbers() {
String input = "(= 4 4 4 4 5 4 4 4 4 4)";
assertSExpressionsMatch(evaluateString(input), parseString("nil"));
}
@Test(expected = BadArgumentTypeException.class)
public void testEqualspWithNonNumbers() {
evaluateString("(= 'x 'x)");
}
@Test(expected = TooFewArgumentsException.class)
public void testEqualspWithTooFewArguments() {
evaluateString("(=)");
}
}

View File

@ -0,0 +1,47 @@
package function.builtin;
import static testutil.TestUtilities.*;
import org.junit.Test;
import function.ArgumentValidator.*;
public class EQUALTester {
@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() {
evaluateString("(car '(1 2) '(1 2) \"oh\")");
}
@Test(expected = TooFewArgumentsException.class)
public void testCarWithTooFewArguments() {
evaluateString("(car)");
}
}

View File

@ -23,7 +23,7 @@ public class SExpressionTester {
public void testNilToString() { public void testNilToString() {
String input = "NIL"; String input = "NIL";
assertSExpressionMatchesString(input, Nil.getUniqueInstance()); assertSExpressionMatchesString(input, Nil.getInstance());
} }
@Test @Test
@ -57,7 +57,7 @@ public class SExpressionTester {
@Test @Test
public void testSimpleConsToString() { public void testSimpleConsToString() {
String expected = "(1)"; String expected = "(1)";
Cons cons = new Cons(new LispNumber("1"), Nil.getUniqueInstance()); Cons cons = new Cons(new LispNumber("1"), Nil.getInstance());
assertSExpressionMatchesString(expected, cons); assertSExpressionMatchesString(expected, cons);
} }
@ -67,7 +67,7 @@ public class SExpressionTester {
String expected = "(1 A \"string\")"; String expected = "(1 A \"string\")";
Cons list = new Cons(new LispNumber("1"), Cons list = new Cons(new LispNumber("1"),
new Cons(new Symbol("a"), new Cons(new Symbol("a"),
new Cons(new LispString("\"string\""), Nil.getUniqueInstance()))); new Cons(new LispString("\"string\""), Nil.getInstance())));
assertSExpressionMatchesString(expected, list); assertSExpressionMatchesString(expected, list);
} }
@ -83,7 +83,7 @@ public class SExpressionTester {
@Test @Test
public void testLambdaExpressionToString() { public void testLambdaExpressionToString() {
String expected = "(LAMBDA)"; String expected = "(LAMBDA)";
LambdaExpression lambda = new LambdaExpression(new Cons(new Symbol("lambda"), Nil.getUniqueInstance()), null); LambdaExpression lambda = new LambdaExpression(new Cons(new Symbol("lambda"), Nil.getInstance()), null);
assertSExpressionMatchesString(expected, lambda); assertSExpressionMatchesString(expected, lambda);
} }
@ -91,7 +91,7 @@ public class SExpressionTester {
@Test @Test
public void testLambdaExpressionGetLambdaExpression() { public void testLambdaExpressionGetLambdaExpression() {
String expected = "(LAMBDA)"; String expected = "(LAMBDA)";
LambdaExpression lambda = new LambdaExpression(new Cons(new Symbol("lambda"), Nil.getUniqueInstance()), null); LambdaExpression lambda = new LambdaExpression(new Cons(new Symbol("lambda"), Nil.getInstance()), null);
assertSExpressionMatchesString(expected, lambda.getLambdaExpression()); assertSExpressionMatchesString(expected, lambda.getLambdaExpression());
} }
@ -99,9 +99,9 @@ public class SExpressionTester {
@Test @Test
public void testLambdaExpressionGetFunction() { public void testLambdaExpressionGetFunction() {
String expected = "(LAMBDA)"; String expected = "(LAMBDA)";
UserDefinedFunction function = new UserDefinedFunction(expected, Nil.getUniqueInstance(), UserDefinedFunction function = new UserDefinedFunction(expected, Nil.getInstance(),
Nil.getUniqueInstance()); Nil.getInstance());
LambdaExpression lambda = new LambdaExpression(new Cons(new Symbol("lambda"), Nil.getUniqueInstance()), LambdaExpression lambda = new LambdaExpression(new Cons(new Symbol("lambda"), Nil.getInstance()),
function); function);
assertEquals(function, lambda.getFunction()); assertEquals(function, lambda.getFunction());
@ -109,28 +109,28 @@ public class SExpressionTester {
@Test @Test
public void testCarOfNilIsNil() { public void testCarOfNilIsNil() {
assertEquals(Nil.getUniqueInstance().getCar(), Nil.getUniqueInstance()); assertEquals(Nil.getInstance().getCar(), Nil.getInstance());
} }
@Test @Test
public void testCdrOfNilIsNil() { public void testCdrOfNilIsNil() {
assertEquals(Nil.getUniqueInstance().getCdr(), Nil.getUniqueInstance()); assertEquals(Nil.getInstance().getCdr(), Nil.getInstance());
} }
@Test @Test
public void afterSettingCarOfNil_ShouldStillBeNil() { public void afterSettingCarOfNil_ShouldStillBeNil() {
Cons nil = Nil.getUniqueInstance(); Cons nil = Nil.getInstance();
nil.setCar(new LispNumber("2")); nil.setCar(new LispNumber("2"));
assertEquals(nil.getCar(), Nil.getUniqueInstance()); assertEquals(nil.getCar(), Nil.getInstance());
} }
@Test @Test
public void afterSettingCdrOfNil_ShouldStillBeNil() { public void afterSettingCdrOfNil_ShouldStillBeNil() {
Cons nil = Nil.getUniqueInstance(); Cons nil = Nil.getInstance();
nil.setCdr(new LispNumber("2")); nil.setCdr(new LispNumber("2"));
assertEquals(nil.getCdr(), Nil.getUniqueInstance()); assertEquals(nil.getCdr(), Nil.getInstance());
} }
@Test @Test

View File

@ -35,8 +35,8 @@ public class SymbolTableTester {
@Test @Test
public void redefineSymbolValue() { public void redefineSymbolValue() {
symbolTable.put("symbol", Symbol.T); symbolTable.put("symbol", Symbol.T);
symbolTable.put("symbol", Nil.getUniqueInstance()); symbolTable.put("symbol", Nil.getInstance());
assertEquals(symbolTable.get("symbol"), Nil.getUniqueInstance()); assertEquals(symbolTable.get("symbol"), Nil.getInstance());
} }
@Test @Test

View File

@ -18,7 +18,7 @@ public final class SExpressionTypeAssertions {
} }
public static void assertNil(SExpression sExpression) { public static void assertNil(SExpression sExpression) {
assertEquals(sExpression, Nil.getUniqueInstance()); assertEquals(sExpression, Nil.getInstance());
assertTrue(sExpression.atomp()); assertTrue(sExpression.atomp());
assertFalse(sExpression.consp()); assertFalse(sExpression.consp());