Added unit tests and did some refactoring
This commit is contained in:
parent
621ab9f2cb
commit
c4531b25e2
|
@ -8,65 +8,47 @@ import table.SymbolTable;
|
||||||
|
|
||||||
public class UserDefinedFunction extends LispFunction {
|
public class UserDefinedFunction extends LispFunction {
|
||||||
|
|
||||||
// the number of arguments that this user-defined function takes.
|
private ArgumentValidator argumentValidator;
|
||||||
private final int NUM_ARGS;
|
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
private Cons body;
|
private Cons body;
|
||||||
private Cons lexpr;
|
private Cons lambdaExpression;
|
||||||
private SymbolTable environment;
|
private SymbolTable environment;
|
||||||
private ArrayList<String> parameters;
|
private ArrayList<String> formalParameters;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new user-defined function with the specified name, lambda list
|
* Create a new user-defined function with the specified name, lambda list and body.
|
||||||
* and body.
|
|
||||||
*
|
*
|
||||||
* @param name
|
* @param name
|
||||||
* the name of this user-defined function
|
* the name of this user-defined function
|
||||||
* @param lambdaList
|
* @param lambdaList
|
||||||
* a list of the formal parameters of this user-defined function (MUST BE
|
* a list of the formal parameters of this user-defined function (MUST BE A PROPER
|
||||||
* A PROPER LIST)
|
* LIST)
|
||||||
* @param body
|
* @param body
|
||||||
* the body of this user-defined function (MUST BE A PROPER LIST)
|
* the body of this user-defined function (MUST BE A PROPER LIST)
|
||||||
*/
|
*/
|
||||||
public UserDefinedFunction(String name, Cons lambdaList, Cons body) {
|
public UserDefinedFunction(String name, Cons lambdaList, Cons body) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.body = body;
|
this.body = body;
|
||||||
this.lexpr = new Cons(new Symbol(name), new Cons(lambdaList, body));
|
this.lambdaExpression = new Cons(new Symbol(name), new Cons(lambdaList, body));
|
||||||
this.environment = SETF.getEnvironment();
|
this.environment = SETF.getEnvironment();
|
||||||
this.parameters = new ArrayList<String>();
|
this.formalParameters = new ArrayList<String>();
|
||||||
|
|
||||||
// retrieve the names of all the formal parameters of this function
|
for (; lambdaList.consp(); lambdaList = (Cons) lambdaList.getCdr())
|
||||||
while (lambdaList.consp()) {
|
this.formalParameters.add(lambdaList.getCar().toString());
|
||||||
this.parameters.add(lambdaList.getCar().toString());
|
|
||||||
|
|
||||||
lambdaList = (Cons) lambdaList.getCdr();
|
this.argumentValidator = new ArgumentValidator(this.name);
|
||||||
}
|
this.argumentValidator.setExactNumberOfArguments(this.formalParameters.size());
|
||||||
|
|
||||||
this.NUM_ARGS = this.parameters.size();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public SExpression call(Cons argList) {
|
public SExpression call(Cons argList) {
|
||||||
// retrieve the number of arguments passed to this function
|
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(name), argList);
|
|
||||||
String errMsg = "too " +
|
|
||||||
((argListLength > NUM_ARGS) ? "many" : "few") +
|
|
||||||
" arguments given to " + name + ": " +
|
|
||||||
originalSExpr;
|
|
||||||
|
|
||||||
throw new RuntimeException(errMsg);
|
|
||||||
}
|
|
||||||
|
|
||||||
// push a new symbol table onto this function's environment (for its
|
// push a new symbol table onto this function's environment (for its
|
||||||
// parameters)
|
// parameters)
|
||||||
environment = new SymbolTable(environment);
|
environment = new SymbolTable(environment);
|
||||||
|
|
||||||
// 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 : parameters) {
|
for (String param : formalParameters) {
|
||||||
SExpression currentArg = argList.getCar();
|
SExpression currentArg = argList.getCar();
|
||||||
|
|
||||||
environment.put(param, currentArg);
|
environment.put(param, currentArg);
|
||||||
|
@ -102,14 +84,8 @@ public class UserDefinedFunction extends LispFunction {
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public Cons getLambdaExpression() {
|
||||||
* Return the lambda expression that represents this user-defined function.
|
return lambdaExpression;
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* the lambda expression that represents this user-defined function
|
|
||||||
*/
|
|
||||||
public Cons getLexpr() {
|
|
||||||
return lexpr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ public class SYMBOL_FUNCTION extends LispFunction {
|
||||||
|
|
||||||
UserDefinedFunction udFunction = (UserDefinedFunction) function;
|
UserDefinedFunction udFunction = (UserDefinedFunction) function;
|
||||||
|
|
||||||
return udFunction.getLexpr();
|
return udFunction.getLambdaExpression();
|
||||||
}
|
}
|
||||||
|
|
||||||
// this is a built-in function
|
// this is a built-in function
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
package function;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import sexpression.*;
|
||||||
|
|
||||||
|
public class LispFunctionTester {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEvaluateArguments() {
|
||||||
|
LispFunction lispFunction = new LispFunction() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SExpression call(Cons argList) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
assertTrue(lispFunction.evaluateArguments());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
package function;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import function.ArgumentValidator.*;
|
||||||
|
import sexpression.*;
|
||||||
|
|
||||||
|
public class UserDefinedFunctionTester {
|
||||||
|
|
||||||
|
private static final String FUNCTION_NAME = "TEST";
|
||||||
|
|
||||||
|
private UserDefinedFunction createNoArgumentFunctionThatReturnsNil() {
|
||||||
|
return new UserDefinedFunction(FUNCTION_NAME, Nil.getUniqueInstance(),
|
||||||
|
new Cons(Nil.getUniqueInstance(), Nil.getUniqueInstance()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private UserDefinedFunction createOneArgumentFunctionThatReturnsArgument() {
|
||||||
|
return new UserDefinedFunction(FUNCTION_NAME, new Cons(new Symbol("X"), Nil.getUniqueInstance()),
|
||||||
|
new Cons(new Symbol("X"), Nil.getUniqueInstance()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNilFunctionCall() {
|
||||||
|
UserDefinedFunction function = createNoArgumentFunctionThatReturnsNil();
|
||||||
|
|
||||||
|
assertEquals(Nil.getUniqueInstance(), function.call(Nil.getUniqueInstance()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNilFunctionToString() {
|
||||||
|
UserDefinedFunction function = createNoArgumentFunctionThatReturnsNil();
|
||||||
|
Cons expected = new Cons(new Symbol(FUNCTION_NAME),
|
||||||
|
new Cons(Nil.getUniqueInstance(),
|
||||||
|
new Cons(Nil.getUniqueInstance(), Nil.getUniqueInstance())));
|
||||||
|
|
||||||
|
assertEquals(expected.toString(), function.getLambdaExpression().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void oneArgumentFunction_ReturnsCorrectValue() {
|
||||||
|
UserDefinedFunction function = createOneArgumentFunctionThatReturnsArgument();
|
||||||
|
SExpression argument = new LispNumber(23);
|
||||||
|
Cons argumentList = new Cons(argument, Nil.getUniqueInstance());
|
||||||
|
|
||||||
|
assertEquals(argument.toString(), function.call(argumentList).toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = TooManyArgumentsException.class)
|
||||||
|
public void oneArgumentFunction_ThrowsExceptionWithTooManyArguments() {
|
||||||
|
UserDefinedFunction function = createOneArgumentFunctionThatReturnsArgument();
|
||||||
|
SExpression argument = new LispNumber(23);
|
||||||
|
Cons argumentList = new Cons(argument, new Cons(argument, Nil.getUniqueInstance()));
|
||||||
|
|
||||||
|
function.call(argumentList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = TooFewArgumentsException.class)
|
||||||
|
public void oneArgumentFunction_ThrowsExceptionWithTooFewArguments() {
|
||||||
|
UserDefinedFunction function = createOneArgumentFunctionThatReturnsArgument();
|
||||||
|
|
||||||
|
function.call(Nil.getUniqueInstance());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue