Added unit tests and refactored defun
This commit is contained in:
parent
5fd22b310f
commit
79648cd96f
|
@ -1,7 +1,9 @@
|
|||
package function.builtin.special;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.HashMap;
|
||||
|
||||
import environment.Environment;
|
||||
import function.*;
|
||||
import function.builtin.EVAL;
|
||||
import function.builtin.cons.LIST;
|
||||
|
@ -12,6 +14,7 @@ public class DEFUN extends LispFunction {
|
|||
private ArgumentValidator argumentValidator;
|
||||
private ArgumentValidator lambdaListIsListValidator;
|
||||
private ArgumentValidator lambdaListValidator;
|
||||
private Environment environment;
|
||||
|
||||
public DEFUN() {
|
||||
this.argumentValidator = new ArgumentValidator("DEFUN");
|
||||
|
@ -23,6 +26,8 @@ public class DEFUN extends LispFunction {
|
|||
|
||||
this.lambdaListValidator = new ArgumentValidator("DEFUN|lambda_list|");
|
||||
this.lambdaListValidator.setEveryArgumentExpectedType(Symbol.class);
|
||||
|
||||
this.environment = Environment.getInstance();
|
||||
}
|
||||
|
||||
public SExpression call(Cons argumentList) {
|
||||
|
@ -37,16 +42,26 @@ public class DEFUN extends LispFunction {
|
|||
lambdaListValidator.validate(lambdaList);
|
||||
|
||||
Cons functionBody = (Cons) remainingArguments.getCdr();
|
||||
UserDefinedFunction function = new UserDefinedFunction(functionName.toString(), lambdaList, functionBody);
|
||||
HashMap<String, LispFunction> functionTable = EVAL.getFunctionTable();
|
||||
|
||||
if (functionTable.containsKey(functionName.toString()))
|
||||
System.out.println("WARNING: redefining function " + functionName.toString());
|
||||
if (isAlreadyDefined(functionName, functionTable))
|
||||
printWarning(functionName);
|
||||
|
||||
functionTable.put(functionName.toString(), new UserDefinedFunction(functionName.toString(), lambdaList, functionBody));
|
||||
functionTable.put(functionName.toString(), function);
|
||||
|
||||
return functionName;
|
||||
}
|
||||
|
||||
private boolean isAlreadyDefined(SExpression functionName, HashMap<String, LispFunction> functionTable) {
|
||||
return functionTable.containsKey(functionName.toString());
|
||||
}
|
||||
|
||||
private void printWarning(SExpression functionName) {
|
||||
String message = MessageFormat.format("WARNING: redefining function {0}", functionName.toString());
|
||||
environment.getOutput().println(message);
|
||||
}
|
||||
|
||||
public boolean evaluateArguments() {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -1,13 +1,29 @@
|
|||
package function.builtin.special;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static testutil.TestUtilities.*;
|
||||
|
||||
import org.junit.Test;
|
||||
import java.io.*;
|
||||
|
||||
import org.junit.*;
|
||||
|
||||
import environment.Environment;
|
||||
import function.ArgumentValidator.*;
|
||||
|
||||
public class DEFUNTester {
|
||||
|
||||
private ByteArrayOutputStream outputStream;
|
||||
|
||||
private void assertPrinted(String expected) {
|
||||
assertEquals(expected, outputStream.toString());
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
this.outputStream = new ByteArrayOutputStream();
|
||||
Environment.getInstance().setOutput(new PrintStream(outputStream));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefun() {
|
||||
String input = "(defun f () nil)";
|
||||
|
@ -16,6 +32,24 @@ public class DEFUNTester {
|
|||
assertSExpressionsMatch(parseString("()"), evaluateString("(f)"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void redefineFunction_DisplaysWarning() {
|
||||
String input = "(defun myFunction () nil)";
|
||||
evaluateString(input);
|
||||
evaluateString(input);
|
||||
|
||||
assertPrinted("WARNING: redefining function MYFUNCTION\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void redefineFunction_ActuallyRedefinesFunction() {
|
||||
evaluateString("(defun myFunction2 () nil)");
|
||||
evaluateString("(defun myFunction2 () T)");
|
||||
|
||||
assertPrinted("WARNING: redefining function MYFUNCTION2\n");
|
||||
assertSExpressionsMatch(parseString("t"), evaluateString("(myFunction2)"));
|
||||
}
|
||||
|
||||
@Test(expected = DottedArgumentListException.class)
|
||||
public void testDefunWithDottedLambdaList() {
|
||||
String input = "(funcall 'defun 'x (cons 'a 'b) ())";
|
||||
|
|
Loading…
Reference in New Issue