diff --git a/lisp/unit-test.lisp b/lisp/unit-test.lisp index 7e2e40d..15f297a 100644 --- a/lisp/unit-test.lisp +++ b/lisp/unit-test.lisp @@ -1,7 +1,7 @@ (defun run-unit-test (unit-test) (cond - ((funcall unit-test) (print (cons (symbol-function unit-test) T))) - (T (print (cons (symbol-function unit-test) 'F))) + ((funcall unit-test) (print (cons (symbol-function unit-test) T)) T) + (T (print (cons (symbol-function unit-test) 'F)) NIL) ) ) @@ -12,5 +12,5 @@ ) (defun unit (test-suite) - (cond ((run-test-suite test-suite) T)) + (apply 'and (run-test-suite test-suite)) ) diff --git a/src/function/builtin/special/AND.java b/src/function/builtin/special/AND.java new file mode 100644 index 0000000..55de758 --- /dev/null +++ b/src/function/builtin/special/AND.java @@ -0,0 +1,38 @@ +package function.builtin.special; + +import function.*; +import function.builtin.EVAL; +import sexpression.*; + +public class AND extends LispFunction { + + private ArgumentValidator argumentValidator; + + public AND() { + this.argumentValidator = new ArgumentValidator("AND"); + } + + public SExpression call(Cons argumentList) { + argumentValidator.validate(argumentList); + + return callTailRecursive(argumentList, Symbol.T); + } + + private SExpression callTailRecursive(Cons argumentList, SExpression lastValue) { + SExpression currentValue = EVAL.eval(argumentList.getCar()); + Cons remainingValues = (Cons) argumentList.getCdr(); + + if (argumentList.nullp()) + return lastValue; + + if (currentValue.nullp()) + return currentValue; + + return callTailRecursive(remainingValues, currentValue); + } + + public boolean evaluateArguments() { + return false; + } + +} diff --git a/src/function/builtin/special/OR.java b/src/function/builtin/special/OR.java new file mode 100644 index 0000000..d6d971d --- /dev/null +++ b/src/function/builtin/special/OR.java @@ -0,0 +1,35 @@ +package function.builtin.special; + +import function.*; +import function.builtin.EVAL; +import sexpression.*; + +public class OR extends LispFunction { + + private ArgumentValidator argumentValidator; + + public OR() { + this.argumentValidator = new ArgumentValidator("OR"); + } + + public SExpression call(Cons argumentList) { + argumentValidator.validate(argumentList); + + return callTailRecursive(argumentList); + } + + private SExpression callTailRecursive(Cons argumentList) { + SExpression currentValue = EVAL.eval(argumentList.getCar()); + Cons remainingValues = (Cons) argumentList.getCdr(); + + if (remainingValues.nullp() || !currentValue.nullp()) + return currentValue; + + return callTailRecursive(remainingValues); + } + + public boolean evaluateArguments() { + return false; + } + +} diff --git a/src/table/FunctionTable.java b/src/table/FunctionTable.java index 7ce6ab6..6366e4f 100644 --- a/src/table/FunctionTable.java +++ b/src/table/FunctionTable.java @@ -41,6 +41,7 @@ public class FunctionTable { functionTable.put("<", new LESSP()); functionTable.put("=", new EQUALSP()); functionTable.put(">", new GREATERP()); + functionTable.put("AND", new AND()); functionTable.put("APPLY", new APPLY()); functionTable.put("ATOM", new ATOM()); functionTable.put("CAR", new CAR()); @@ -62,6 +63,7 @@ public class FunctionTable { functionTable.put("LISTP", new LISTP()); functionTable.put("LOAD", new LOAD()); functionTable.put("NULL", new NULL()); + functionTable.put("OR", new OR()); functionTable.put("PRINT", new PRINT()); functionTable.put("QUOTE", new QUOTE()); functionTable.put("REST", new CDR()); diff --git a/test/function/builtin/special/ANDTester.java b/test/function/builtin/special/ANDTester.java new file mode 100644 index 0000000..429d29c --- /dev/null +++ b/test/function/builtin/special/ANDTester.java @@ -0,0 +1,80 @@ +package function.builtin.special; + +import static testutil.TestUtilities.*; +import static testutil.TypeAssertions.*; + +import org.junit.*; + +import function.builtin.EVAL.UndefinedSymbolException; +import sexpression.LispNumber; +import table.ExecutionContext; + +public class ANDTester { + + private ExecutionContext executionContext; + + public ANDTester() { + this.executionContext = ExecutionContext.getInstance(); + } + + @Before + public void setUp() { + executionContext.clearContext(); + } + + @After + public void tearDown() { + executionContext.clearContext(); + } + + @Test + public void andByItself() { + String input = "(and)"; + + assertT(evaluateString(input)); + } + + @Test + public void andWithNil() { + String input = "(and nil)"; + + assertNil(evaluateString(input)); + } + + @Test + public void andWithT() { + String input = "(and t)"; + + assertT(evaluateString(input)); + } + + @Test + public void andWithNumber() { + String input = "(and 7)"; + + assertSExpressionsMatch(new LispNumber("7"), evaluateString(input)); + } + + @Test + public void andWithSeveralValues() { + String input = "(and t t nil t t)"; + + assertNil(evaluateString(input)); + } + + @Test + public void andWithSeveralNumbers() { + String input = "(and 1 2 3)"; + + assertSExpressionsMatch(new LispNumber("3"), evaluateString(input)); + } + + @Test(expected = UndefinedSymbolException.class) + public void andShortCircuits() { + String input = "(and nil (setf x 22))"; + + assertNil(evaluateString(input)); + evaluateString("x"); + } + +} diff --git a/test/function/builtin/special/LETTester.java b/test/function/builtin/special/LETTester.java index 6d1e0ca..8e350c5 100644 --- a/test/function/builtin/special/LETTester.java +++ b/test/function/builtin/special/LETTester.java @@ -22,6 +22,11 @@ public class LETTester { executionContext.clearContext(); } + @After + public void tearDown() { + executionContext.clearContext(); + } + @Test public void simpleLet() { String input = "(let ((x 1)) x)"; diff --git a/test/function/builtin/special/ORTester.java b/test/function/builtin/special/ORTester.java new file mode 100644 index 0000000..c3fc266 --- /dev/null +++ b/test/function/builtin/special/ORTester.java @@ -0,0 +1,80 @@ +package function.builtin.special; + +import static testutil.TestUtilities.*; +import static testutil.TypeAssertions.*; + +import org.junit.*; + +import function.builtin.EVAL.UndefinedSymbolException; +import sexpression.LispNumber; +import table.ExecutionContext; + +public class ORTester { + + private ExecutionContext executionContext; + + public ORTester() { + this.executionContext = ExecutionContext.getInstance(); + } + + @Before + public void setUp() { + executionContext.clearContext(); + } + + @After + public void tearDown() { + executionContext.clearContext(); + } + + @Test + public void orByItself() { + String input = "(or)"; + + assertNil(evaluateString(input)); + } + + @Test + public void orWithNil() { + String input = "(or nil)"; + + assertNil(evaluateString(input)); + } + + @Test + public void orWithT() { + String input = "(or t)"; + + assertT(evaluateString(input)); + } + + @Test + public void orWithNumber() { + String input = "(or 7)"; + + assertSExpressionsMatch(new LispNumber("7"), evaluateString(input)); + } + + @Test + public void orWithSeveralValues() { + String input = "(or nil nil nil t nil)"; + + assertT(evaluateString(input)); + } + + @Test + public void orWithSeveralNumbers() { + String input = "(or 1 2 3)"; + + assertSExpressionsMatch(new LispNumber("1"), evaluateString(input)); + } + + @Test(expected = UndefinedSymbolException.class) + public void orShortCircuits() { + String input = "(or t (setf x 22))"; + + assertT(evaluateString(input)); + evaluateString("x"); + } + +} diff --git a/test/function/builtin/special/SETFTester.java b/test/function/builtin/special/SETFTester.java index c481cf3..27d9b5a 100644 --- a/test/function/builtin/special/SETFTester.java +++ b/test/function/builtin/special/SETFTester.java @@ -11,9 +11,9 @@ import sexpression.LispNumber; import table.*; public class SETFTester { - + private ExecutionContext executionContext; - + public SETFTester() { this.executionContext = ExecutionContext.getInstance(); } @@ -23,6 +23,11 @@ public class SETFTester { executionContext.clearContext(); } + @After + public void tearDown() { + executionContext.clearContext(); + } + @Test public void testSetf() { evaluateString("(setf a 23)");