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