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 function.*;
|
||||||
import sexpression.*;
|
import sexpression.*;
|
||||||
|
|
||||||
/**
|
|
||||||
* <code>APPLY</code> represents the APPLY function in Lisp.
|
|
||||||
*/
|
|
||||||
public class APPLY extends LispFunction {
|
public class APPLY extends LispFunction {
|
||||||
|
|
||||||
/**
|
private static final int NUMBER_OF_ARGUMENTS = 2;
|
||||||
* Call APPLY with the specified argument list.
|
private ArgumentValidator argumentValidator;
|
||||||
*
|
|
||||||
* @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>
|
|
||||||
*/
|
|
||||||
public static SExpression apply(Cons argList) {
|
public static SExpression apply(Cons argList) {
|
||||||
return new APPLY().call(argList);
|
return new APPLY().call(argList);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The number of arguments that APPLY takes.
|
public APPLY() {
|
||||||
private static final int NUM_ARGS = 2;
|
this.argumentValidator = new ArgumentValidator("APPLY");
|
||||||
|
this.argumentValidator.setExactNumberOfArguments(NUMBER_OF_ARGUMENTS);
|
||||||
|
}
|
||||||
|
|
||||||
public SExpression call(Cons argList) {
|
public SExpression call(Cons argList) {
|
||||||
// retrieve the number of arguments passed to APPLY
|
argumentValidator.validate(argList);
|
||||||
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("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();
|
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 (argumentList.listp()) {
|
||||||
if (cadr.listp()) {
|
LispFunction function = EVAL.lookupFunction(functionName.toString());
|
||||||
LispFunction function = EVAL.lookupFunction(car.toString());
|
|
||||||
|
|
||||||
if (function == null) {
|
if (function == null) {
|
||||||
// check if the car of the list is a lambda expression
|
if (functionName.functionp()) {
|
||||||
if (car.functionp()) {
|
function = ((LambdaExpression) functionName).getFunction();
|
||||||
function = ((LambdaExpression) car).getFunction();
|
} else if (LAMBDA.isLambdaExpression(functionName)) {
|
||||||
} else if (LAMBDA.isLambdaExpression(car)) {
|
Cons lexpr = (Cons) functionName;
|
||||||
Cons lexpr = (Cons) car;
|
|
||||||
|
|
||||||
function = LAMBDA.createFunction(lexpr);
|
function = LAMBDA.createFunction(lexpr);
|
||||||
} else {
|
} 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) argumentList);
|
||||||
return function.call((Cons) cadr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// the second argument is not a list
|
throw new RuntimeException("APPLY: " + argumentList + " is not a list");
|
||||||
throw new RuntimeException("APPLY: " + cadr + " is not a list");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,32 +1,23 @@
|
||||||
package function.builtin;
|
package function.builtin;
|
||||||
|
|
||||||
import function.LispFunction;
|
import function.*;
|
||||||
import sexpression.*;
|
import sexpression.*;
|
||||||
|
|
||||||
/**
|
|
||||||
* <code>ATOM</code> represents the ATOM function in Lisp.
|
|
||||||
*/
|
|
||||||
public class ATOM extends LispFunction {
|
public class ATOM extends LispFunction {
|
||||||
|
|
||||||
// The number of arguments that ATOM takes.
|
private static final int NUMBER_OF_ARGUMENTS = 1;
|
||||||
private static final int NUM_ARGS = 1;
|
private ArgumentValidator argumentValidator;
|
||||||
|
|
||||||
public SExpression call(Cons argList) {
|
public ATOM() {
|
||||||
// retrieve the number of arguments passed to ATOM
|
this.argumentValidator = new ArgumentValidator("ATOM");
|
||||||
int argListLength = LENGTH.getLength(argList);
|
this.argumentValidator.setExactNumberOfArguments(NUMBER_OF_ARGUMENTS);
|
||||||
|
}
|
||||||
|
|
||||||
// make sure we have received the proper number of arguments
|
public SExpression call(Cons argumentList) {
|
||||||
if (argListLength != NUM_ARGS) {
|
argumentValidator.validate(argumentList);
|
||||||
Cons originalSExpr = new Cons(new Symbol("ATOM"), argList);
|
SExpression argument = argumentList.getCar();
|
||||||
String errMsg = "too " + ((argListLength > NUM_ARGS) ? "many" : "few") + " arguments given to ATOM: "
|
|
||||||
+ originalSExpr;
|
|
||||||
|
|
||||||
throw new RuntimeException(errMsg);
|
return argument.atomp() ? Symbol.T : Nil.getUniqueInstance();
|
||||||
}
|
|
||||||
|
|
||||||
SExpression arg = argList.getCar();
|
|
||||||
|
|
||||||
return (arg.atomp() ? Symbol.T : Nil.getUniqueInstance());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package function;
|
package function;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static testutil.TestUtilities.*;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
@ -35,7 +36,7 @@ public class UserDefinedFunctionTester {
|
||||||
new Cons(Nil.getUniqueInstance(),
|
new Cons(Nil.getUniqueInstance(),
|
||||||
new Cons(Nil.getUniqueInstance(), Nil.getUniqueInstance())));
|
new Cons(Nil.getUniqueInstance(), Nil.getUniqueInstance())));
|
||||||
|
|
||||||
assertEquals(expected.toString(), function.getLambdaExpression().toString());
|
assertSExpressionsMatch(expected, function.getLambdaExpression());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -44,7 +45,7 @@ public class UserDefinedFunctionTester {
|
||||||
SExpression argument = new LispNumber(23);
|
SExpression argument = new LispNumber(23);
|
||||||
Cons argumentList = new Cons(argument, Nil.getUniqueInstance());
|
Cons argumentList = new Cons(argument, Nil.getUniqueInstance());
|
||||||
|
|
||||||
assertEquals(argument.toString(), function.call(argumentList).toString());
|
assertSExpressionsMatch(argument, function.call(argumentList));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = TooManyArgumentsException.class)
|
@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;
|
package parser;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
import static parser.SExpressionTypeAssertions.*;
|
import static testutil.SExpressionTypeAssertions.*;
|
||||||
import static testutil.TestUtilities.createIOExceptionThrowingInputStream;
|
import static testutil.TestUtilities.createIOExceptionThrowingInputStream;
|
||||||
import static testutil.TestUtilities.createInputStreamFromString;
|
import static testutil.TestUtilities.createInputStreamFromString;
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
package parser;
|
package testutil;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
import sexpression.Nil;
|
import sexpression.*;
|
||||||
import sexpression.SExpression;
|
|
||||||
|
|
||||||
public final class SExpressionTypeAssertions {
|
public final class SExpressionTypeAssertions {
|
||||||
|
|
|
@ -1,13 +1,19 @@
|
||||||
package testutil;
|
package testutil;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
|
||||||
|
import function.builtin.EVAL;
|
||||||
|
import parser.LispParser;
|
||||||
|
import sexpression.SExpression;
|
||||||
|
|
||||||
public final class TestUtilities {
|
public final class TestUtilities {
|
||||||
|
|
||||||
public static InputStream createInputStreamFromString(String string) {
|
public static InputStream createInputStreamFromString(String string) {
|
||||||
return new ByteArrayInputStream(string.getBytes());
|
return new ByteArrayInputStream(string.getBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static InputStream createIOExceptionThrowingInputStream() {
|
public static InputStream createIOExceptionThrowingInputStream() {
|
||||||
return new InputStream() {
|
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