Started writing tests for the builtin functions
This commit is contained in:
parent
715de2f220
commit
9bea0e6533
|
@ -3,65 +3,46 @@ package function.builtin;
|
|||
import function.*;
|
||||
import sexpression.*;
|
||||
|
||||
/**
|
||||
* <code>APPLY</code> represents the APPLY function in Lisp.
|
||||
*/
|
||||
public class APPLY extends LispFunction {
|
||||
|
||||
/**
|
||||
* Call APPLY with the specified argument list.
|
||||
*
|
||||
* @param argList
|
||||
* the list of arguments to be sent to APPLY (MUST BE A PROPER LIST)
|
||||
* @return the result of evaluating APPLY on <code>argList</code>
|
||||
*/
|
||||
private static final int NUMBER_OF_ARGUMENTS = 2;
|
||||
private ArgumentValidator argumentValidator;
|
||||
|
||||
public static SExpression apply(Cons argList) {
|
||||
return new APPLY().call(argList);
|
||||
}
|
||||
|
||||
// The number of arguments that APPLY takes.
|
||||
private static final int NUM_ARGS = 2;
|
||||
public APPLY() {
|
||||
this.argumentValidator = new ArgumentValidator("APPLY");
|
||||
this.argumentValidator.setExactNumberOfArguments(NUMBER_OF_ARGUMENTS);
|
||||
}
|
||||
|
||||
public SExpression call(Cons argList) {
|
||||
// retrieve the number of arguments passed to APPLY
|
||||
int argListLength = LENGTH.getLength(argList);
|
||||
argumentValidator.validate(argList);
|
||||
|
||||
// make sure we have received the proper number of arguments
|
||||
if (argListLength != NUM_ARGS) {
|
||||
Cons originalSExpr = new Cons(new Symbol("APPLY"), argList);
|
||||
String errMsg = "too " + ((argListLength > NUM_ARGS) ? "many" : "few") + " arguments given to APPLY: "
|
||||
+ originalSExpr;
|
||||
|
||||
throw new RuntimeException(errMsg);
|
||||
}
|
||||
|
||||
SExpression car = argList.getCar(); // function name
|
||||
Cons cdr = (Cons) argList.getCdr();
|
||||
SExpression cadr = cdr.getCar(); // argument list
|
||||
SExpression functionName = argList.getCar();
|
||||
SExpression argumentList = cdr.getCar();
|
||||
|
||||
// make sure the second argument is a list
|
||||
if (cadr.listp()) {
|
||||
LispFunction function = EVAL.lookupFunction(car.toString());
|
||||
if (argumentList.listp()) {
|
||||
LispFunction function = EVAL.lookupFunction(functionName.toString());
|
||||
|
||||
if (function == null) {
|
||||
// check if the car of the list is a lambda expression
|
||||
if (car.functionp()) {
|
||||
function = ((LambdaExpression) car).getFunction();
|
||||
} else if (LAMBDA.isLambdaExpression(car)) {
|
||||
Cons lexpr = (Cons) car;
|
||||
if (functionName.functionp()) {
|
||||
function = ((LambdaExpression) functionName).getFunction();
|
||||
} else if (LAMBDA.isLambdaExpression(functionName)) {
|
||||
Cons lexpr = (Cons) functionName;
|
||||
|
||||
function = LAMBDA.createFunction(lexpr);
|
||||
} else {
|
||||
throw new RuntimeException("undefined function " + car);
|
||||
throw new RuntimeException("undefined function " + functionName);
|
||||
}
|
||||
}
|
||||
|
||||
// apply the given function to the given argument list
|
||||
return function.call((Cons) cadr);
|
||||
return function.call((Cons) argumentList);
|
||||
}
|
||||
|
||||
// the second argument is not a list
|
||||
throw new RuntimeException("APPLY: " + cadr + " is not a list");
|
||||
throw new RuntimeException("APPLY: " + argumentList + " is not a list");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,32 +1,23 @@
|
|||
package function.builtin;
|
||||
|
||||
import function.LispFunction;
|
||||
import function.*;
|
||||
import sexpression.*;
|
||||
|
||||
/**
|
||||
* <code>ATOM</code> represents the ATOM function in Lisp.
|
||||
*/
|
||||
public class ATOM extends LispFunction {
|
||||
|
||||
// The number of arguments that ATOM takes.
|
||||
private static final int NUM_ARGS = 1;
|
||||
private static final int NUMBER_OF_ARGUMENTS = 1;
|
||||
private ArgumentValidator argumentValidator;
|
||||
|
||||
public SExpression call(Cons argList) {
|
||||
// retrieve the number of arguments passed to ATOM
|
||||
int argListLength = LENGTH.getLength(argList);
|
||||
public ATOM() {
|
||||
this.argumentValidator = new ArgumentValidator("ATOM");
|
||||
this.argumentValidator.setExactNumberOfArguments(NUMBER_OF_ARGUMENTS);
|
||||
}
|
||||
|
||||
// make sure we have received the proper number of arguments
|
||||
if (argListLength != NUM_ARGS) {
|
||||
Cons originalSExpr = new Cons(new Symbol("ATOM"), argList);
|
||||
String errMsg = "too " + ((argListLength > NUM_ARGS) ? "many" : "few") + " arguments given to ATOM: "
|
||||
+ originalSExpr;
|
||||
public SExpression call(Cons argumentList) {
|
||||
argumentValidator.validate(argumentList);
|
||||
SExpression argument = argumentList.getCar();
|
||||
|
||||
throw new RuntimeException(errMsg);
|
||||
}
|
||||
|
||||
SExpression arg = argList.getCar();
|
||||
|
||||
return (arg.atomp() ? Symbol.T : Nil.getUniqueInstance());
|
||||
return argument.atomp() ? Symbol.T : Nil.getUniqueInstance();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package function;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static testutil.TestUtilities.*;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -35,7 +36,7 @@ public class UserDefinedFunctionTester {
|
|||
new Cons(Nil.getUniqueInstance(),
|
||||
new Cons(Nil.getUniqueInstance(), Nil.getUniqueInstance())));
|
||||
|
||||
assertEquals(expected.toString(), function.getLambdaExpression().toString());
|
||||
assertSExpressionsMatch(expected, function.getLambdaExpression());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -44,7 +45,7 @@ public class UserDefinedFunctionTester {
|
|||
SExpression argument = new LispNumber(23);
|
||||
Cons argumentList = new Cons(argument, Nil.getUniqueInstance());
|
||||
|
||||
assertEquals(argument.toString(), function.call(argumentList).toString());
|
||||
assertSExpressionsMatch(argument, function.call(argumentList));
|
||||
}
|
||||
|
||||
@Test(expected = TooManyArgumentsException.class)
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
package function.builtin;
|
||||
|
||||
import static testutil.TestUtilities.*;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import function.ArgumentValidator.*;
|
||||
import sexpression.Cons;
|
||||
|
||||
public class APPLYTester {
|
||||
|
||||
@Test
|
||||
public void testApply() {
|
||||
String input = "(apply '+ '(1 2 3))";
|
||||
|
||||
assertSExpressionsMatch(evaluateString(input), parseString("6"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApplyWithLambdaExpression() {
|
||||
String input = "(apply (lambda (x) (+ x 1)) '(25))";
|
||||
|
||||
assertSExpressionsMatch(evaluateString(input), parseString("26"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApplyWithQuotedLambdaExpression() {
|
||||
String input = "(apply '(lambda (x) (+ x 1)) '(25))";
|
||||
|
||||
assertSExpressionsMatch(evaluateString(input), parseString("26"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStaticApplyCall() {
|
||||
String argumentList = "(+ (25 10))";
|
||||
Cons parsedArgumentList = (Cons) parseString(argumentList);
|
||||
|
||||
assertSExpressionsMatch(APPLY.apply(parsedArgumentList), parseString("35"));
|
||||
}
|
||||
|
||||
@Test(expected = RuntimeException.class)
|
||||
public void testApplyWithUndefinedFunction() {
|
||||
evaluateString("(apply 'f '(1 2 3))");
|
||||
}
|
||||
|
||||
@Test(expected = RuntimeException.class)
|
||||
public void testApplyWithNonListSecondArgument() {
|
||||
evaluateString("(apply '+ '2)");
|
||||
}
|
||||
|
||||
@Test(expected = TooManyArgumentsException.class)
|
||||
public void testApplyWithTooManyArguments() {
|
||||
evaluateString("(apply '1 '2 '3)");
|
||||
}
|
||||
|
||||
@Test(expected = TooFewArgumentsException.class)
|
||||
public void testApplyWithTooFewArguments() {
|
||||
evaluateString("(apply '1)");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package function.builtin;
|
||||
|
||||
import static testutil.TestUtilities.*;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import function.ArgumentValidator.*;
|
||||
|
||||
public class ATOMTester {
|
||||
|
||||
@Test
|
||||
public void testAtom_ReturnsTrue() {
|
||||
String input = "(atom 'a)";
|
||||
|
||||
assertSExpressionsMatch(evaluateString(input), parseString("T"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAtom_ReturnsFalse() {
|
||||
String input = "(atom '(1 2 3))";
|
||||
|
||||
assertSExpressionsMatch(evaluateString(input), parseString("()"));
|
||||
}
|
||||
|
||||
@Test(expected = TooManyArgumentsException.class)
|
||||
public void testApplyWithTooManyArguments() {
|
||||
evaluateString("(atom '1 '2)");
|
||||
}
|
||||
|
||||
@Test(expected = TooFewArgumentsException.class)
|
||||
public void testApplyWithTooFewArguments() {
|
||||
evaluateString("(atom)");
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
package parser;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static parser.SExpressionTypeAssertions.*;
|
||||
import static testutil.SExpressionTypeAssertions.*;
|
||||
import static testutil.TestUtilities.createIOExceptionThrowingInputStream;
|
||||
import static testutil.TestUtilities.createInputStreamFromString;
|
||||
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
package parser;
|
||||
package testutil;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import sexpression.Nil;
|
||||
import sexpression.SExpression;
|
||||
import sexpression.*;
|
||||
|
||||
public final class SExpressionTypeAssertions {
|
||||
|
|
@ -1,13 +1,19 @@
|
|||
package testutil;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import function.builtin.EVAL;
|
||||
import parser.LispParser;
|
||||
import sexpression.SExpression;
|
||||
|
||||
public final class TestUtilities {
|
||||
|
||||
public static InputStream createInputStreamFromString(String string) {
|
||||
return new ByteArrayInputStream(string.getBytes());
|
||||
}
|
||||
|
||||
|
||||
public static InputStream createIOExceptionThrowingInputStream() {
|
||||
return new InputStream() {
|
||||
|
||||
|
@ -17,4 +23,18 @@ public final class TestUtilities {
|
|||
};
|
||||
}
|
||||
|
||||
public static SExpression evaluateString(String input) {
|
||||
return EVAL.eval(parseString(input));
|
||||
}
|
||||
|
||||
public static SExpression parseString(String input) {
|
||||
InputStream stringInputStream = TestUtilities.createInputStreamFromString(input);
|
||||
|
||||
return new LispParser(stringInputStream, "testFile").getNextSExpression();
|
||||
}
|
||||
|
||||
public static void assertSExpressionsMatch(SExpression one, SExpression two) {
|
||||
assertEquals(one.toString(), two.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue