Added unit tests and did some refactoring

This commit is contained in:
Mike Cifelli 2016-12-20 12:03:37 -05:00
parent 621ab9f2cb
commit c4531b25e2
4 changed files with 109 additions and 43 deletions

View File

@ -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;
} }
} }

View File

@ -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

View File

@ -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());
}
}

View File

@ -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());
}
}