From 73bcd4da3874c8211c0d6f0f3752dd322cc7135d Mon Sep 17 00:00:00 2001 From: Mike Cifelli Date: Sun, 28 Oct 2018 20:22:45 -0400 Subject: [PATCH] Convert Begin and If to kotlin --- .../kotlin/function/builtin/special/Begin.kt | 31 +++++++ .../kotlin/function/builtin/special/IF.java | 52 ------------ .../kotlin/function/builtin/special/If.kt | 31 +++++++ .../function/builtin/special/PROGN.java | 40 --------- .../function/builtin/special/QUOTE.java | 25 ------ .../kotlin/function/builtin/special/Quote.kt | 21 +++++ .../function/builtin/special/BeginTest.kt | 43 ++++++++++ .../builtin/special/DefineSpecialTest.kt | 2 + .../function/builtin/special/DefmacroTest.kt | 2 + .../function/builtin/special/DefunTest.kt | 2 + .../function/builtin/special/IFTest.java | 75 ---------------- .../kotlin/function/builtin/special/IfTest.kt | 85 +++++++++++++++++++ .../function/builtin/special/PROGNTest.java | 42 --------- .../function/builtin/special/QUOTETest.java | 37 -------- .../function/builtin/special/QuoteTest.kt | 43 ++++++++++ 15 files changed, 260 insertions(+), 271 deletions(-) create mode 100644 src/main/kotlin/function/builtin/special/Begin.kt delete mode 100644 src/main/kotlin/function/builtin/special/IF.java create mode 100644 src/main/kotlin/function/builtin/special/If.kt delete mode 100644 src/main/kotlin/function/builtin/special/PROGN.java delete mode 100644 src/main/kotlin/function/builtin/special/QUOTE.java create mode 100644 src/main/kotlin/function/builtin/special/Quote.kt create mode 100644 src/test/kotlin/function/builtin/special/BeginTest.kt delete mode 100644 src/test/kotlin/function/builtin/special/IFTest.java create mode 100644 src/test/kotlin/function/builtin/special/IfTest.kt delete mode 100644 src/test/kotlin/function/builtin/special/PROGNTest.java delete mode 100644 src/test/kotlin/function/builtin/special/QUOTETest.java create mode 100644 src/test/kotlin/function/builtin/special/QuoteTest.kt diff --git a/src/main/kotlin/function/builtin/special/Begin.kt b/src/main/kotlin/function/builtin/special/Begin.kt new file mode 100644 index 0000000..34c4e1e --- /dev/null +++ b/src/main/kotlin/function/builtin/special/Begin.kt @@ -0,0 +1,31 @@ +package function.builtin.special + +import function.ArgumentValidator +import function.FunctionNames +import function.LispSpecialFunction +import function.builtin.Eval.Companion.eval +import sexpression.Cons +import sexpression.Nil +import sexpression.SExpression + +@FunctionNames("PROGN", "BEGIN") +class Begin(name: String) : LispSpecialFunction() { + + private val argumentValidator = ArgumentValidator(name) + + override fun call(argumentList: Cons): SExpression { + argumentValidator.validate(argumentList) + + return callTailRecursive(argumentList, Nil) + } + + private tailrec fun callTailRecursive(argumentList: Cons, lastValue: SExpression): SExpression { + if (argumentList.isNull) + return lastValue + + val currentValue = eval(argumentList.first) + val remainingValues = argumentList.rest as Cons + + return callTailRecursive(remainingValues, currentValue) + } +} diff --git a/src/main/kotlin/function/builtin/special/IF.java b/src/main/kotlin/function/builtin/special/IF.java deleted file mode 100644 index 3970908..0000000 --- a/src/main/kotlin/function/builtin/special/IF.java +++ /dev/null @@ -1,52 +0,0 @@ -package function.builtin.special; - -import function.ArgumentValidator; -import function.FunctionNames; -import function.LispSpecialFunction; -import sexpression.Cons; -import sexpression.SExpression; - -import static function.builtin.Eval.eval; - -@FunctionNames({ "IF" }) -public class IF extends LispSpecialFunction { - - private ArgumentValidator argumentValidator; - - public IF(String name) { - this.argumentValidator = new ArgumentValidator(name); - this.argumentValidator.setMinimumNumberOfArguments(2); - this.argumentValidator.setMaximumNumberOfArguments(3); - } - - @Override - public SExpression call(Cons argumentList) { - argumentValidator.validate(argumentList); - - SExpression test = eval(argumentList.getFirst()); - SExpression thenForm = getThenForm(argumentList); - SExpression elseForm = getElseForm(argumentList); - - return isNil(test) ? eval(elseForm) : eval(thenForm); - } - - private boolean isNil(SExpression test) { - return test.isNull(); - } - - private SExpression getThenForm(Cons argumentList) { - Cons expressions = getRestOfList(argumentList); - - return expressions.getFirst(); - } - - private Cons getRestOfList(Cons argumentList) { - return (Cons) argumentList.getRest(); - } - - private SExpression getElseForm(Cons argumentList) { - Cons expressions = getRestOfList(argumentList); - - return getRestOfList(expressions).getFirst(); - } -} diff --git a/src/main/kotlin/function/builtin/special/If.kt b/src/main/kotlin/function/builtin/special/If.kt new file mode 100644 index 0000000..34544eb --- /dev/null +++ b/src/main/kotlin/function/builtin/special/If.kt @@ -0,0 +1,31 @@ +package function.builtin.special + +import function.ArgumentValidator +import function.FunctionNames +import function.LispSpecialFunction +import function.builtin.Eval.Companion.eval +import sexpression.Cons +import sexpression.SExpression + +@FunctionNames("IF") +class If(name: String) : LispSpecialFunction() { + + private val argumentValidator = ArgumentValidator(name).apply { + setMinimumNumberOfArguments(2) + setMaximumNumberOfArguments(3) + } + + override fun call(argumentList: Cons): SExpression { + argumentValidator.validate(argumentList) + + val test = eval(argumentList.first) + val thenForm = getThenForm(argumentList) + val elseForm = getElseForm(argumentList) + + return if (test.isNull) eval(elseForm) else eval(thenForm) + } + + private fun getRestOfList(argumentList: Cons) = argumentList.rest as Cons + private fun getThenForm(argumentList: Cons) = getRestOfList(argumentList).first + private fun getElseForm(argumentList: Cons) = getRestOfList(argumentList).let { getRestOfList(it).first } +} diff --git a/src/main/kotlin/function/builtin/special/PROGN.java b/src/main/kotlin/function/builtin/special/PROGN.java deleted file mode 100644 index 0b99c07..0000000 --- a/src/main/kotlin/function/builtin/special/PROGN.java +++ /dev/null @@ -1,40 +0,0 @@ -package function.builtin.special; - -import function.ArgumentValidator; -import function.FunctionNames; -import function.LispSpecialFunction; -import recursion.TailCall; -import sexpression.Cons; -import sexpression.Nil; -import sexpression.SExpression; - -import static function.builtin.Eval.eval; -import static recursion.TailCalls.done; -import static recursion.TailCalls.tailCall; - -@FunctionNames({ "PROGN", "BEGIN" }) -public class PROGN extends LispSpecialFunction { - - private ArgumentValidator argumentValidator; - - public PROGN(String name) { - this.argumentValidator = new ArgumentValidator(name); - } - - @Override - public SExpression call(Cons argumentList) { - argumentValidator.validate(argumentList); - - return callTailRecursive(argumentList, Nil.INSTANCE).invoke(); - } - - private TailCall callTailRecursive(Cons argumentList, SExpression lastValue) { - if (argumentList.isNull()) - return done(lastValue); - - SExpression currentValue = eval(argumentList.getFirst()); - Cons remainingValues = (Cons) argumentList.getRest(); - - return tailCall(() -> callTailRecursive(remainingValues, currentValue)); - } -} diff --git a/src/main/kotlin/function/builtin/special/QUOTE.java b/src/main/kotlin/function/builtin/special/QUOTE.java deleted file mode 100644 index e0bcb3b..0000000 --- a/src/main/kotlin/function/builtin/special/QUOTE.java +++ /dev/null @@ -1,25 +0,0 @@ -package function.builtin.special; - -import function.ArgumentValidator; -import function.FunctionNames; -import function.LispSpecialFunction; -import sexpression.Cons; -import sexpression.SExpression; - -@FunctionNames({ "QUOTE" }) -public class QUOTE extends LispSpecialFunction { - - private ArgumentValidator argumentValidator; - - public QUOTE(String name) { - this.argumentValidator = new ArgumentValidator(name); - this.argumentValidator.setExactNumberOfArguments(1); - } - - @Override - public SExpression call(Cons argumentList) { - argumentValidator.validate(argumentList); - - return argumentList.getFirst(); - } -} diff --git a/src/main/kotlin/function/builtin/special/Quote.kt b/src/main/kotlin/function/builtin/special/Quote.kt new file mode 100644 index 0000000..107fa04 --- /dev/null +++ b/src/main/kotlin/function/builtin/special/Quote.kt @@ -0,0 +1,21 @@ +package function.builtin.special + +import function.ArgumentValidator +import function.FunctionNames +import function.LispSpecialFunction +import sexpression.Cons +import sexpression.SExpression + +@FunctionNames("QUOTE") +class Quote(name: String) : LispSpecialFunction() { + + private val argumentValidator = ArgumentValidator(name).apply { + setExactNumberOfArguments(1) + } + + override fun call(argumentList: Cons): SExpression { + argumentValidator.validate(argumentList) + + return argumentList.first + } +} diff --git a/src/test/kotlin/function/builtin/special/BeginTest.kt b/src/test/kotlin/function/builtin/special/BeginTest.kt new file mode 100644 index 0000000..3aceaf6 --- /dev/null +++ b/src/test/kotlin/function/builtin/special/BeginTest.kt @@ -0,0 +1,43 @@ +package function.builtin.special + +import org.junit.jupiter.api.Test +import testutil.LispTestInstance +import testutil.SymbolAndFunctionCleaner +import testutil.TestUtilities.assertSExpressionsMatch +import testutil.TestUtilities.evaluateString +import testutil.TestUtilities.parseString +import testutil.TypeAssertions.assertNil + +@LispTestInstance +class BeginTest : SymbolAndFunctionCleaner() { + + @Test + fun prognWithNoArguments() { + assertNil(evaluateString("(progn)")) + } + + @Test + fun prognWithOneArgument() { + assertSExpressionsMatch(parseString("1"), evaluateString("(progn 1)")) + } + + @Test + fun prognWithSeveralArguments() { + assertSExpressionsMatch(parseString("5"), evaluateString("(progn 1 2 3 4 5)")) + } + + @Test + fun beginWithSeveralArguments() { + assertSExpressionsMatch(parseString("5"), evaluateString("(begin 1 2 3 4 5)")) + } + + @Test + fun prognEvaluatesArgument() { + assertSExpressionsMatch(parseString("1"), evaluateString("(progn (car '(1 2 3)))")) + } + + @Test + fun prognWithDifferentArgumentTypes() { + assertSExpressionsMatch(parseString("pear"), evaluateString("(progn t nil '(1 2) 'pear)")) + } +} diff --git a/src/test/kotlin/function/builtin/special/DefineSpecialTest.kt b/src/test/kotlin/function/builtin/special/DefineSpecialTest.kt index 65a9575..ac0f257 100644 --- a/src/test/kotlin/function/builtin/special/DefineSpecialTest.kt +++ b/src/test/kotlin/function/builtin/special/DefineSpecialTest.kt @@ -10,6 +10,7 @@ import function.UserDefinedFunction.IllegalKeywordRestPositionException import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Assertions.assertThrows import org.junit.jupiter.api.Test +import testutil.LispTestInstance import testutil.SymbolAndFunctionCleaner import testutil.TestUtilities.assertSExpressionsMatch import testutil.TestUtilities.evaluateString @@ -17,6 +18,7 @@ import testutil.TestUtilities.parseString import java.io.ByteArrayOutputStream import java.io.PrintStream +@LispTestInstance class DefineSpecialTest : SymbolAndFunctionCleaner() { private var outputStream = ByteArrayOutputStream() diff --git a/src/test/kotlin/function/builtin/special/DefmacroTest.kt b/src/test/kotlin/function/builtin/special/DefmacroTest.kt index 2c44fcb..226a536 100644 --- a/src/test/kotlin/function/builtin/special/DefmacroTest.kt +++ b/src/test/kotlin/function/builtin/special/DefmacroTest.kt @@ -10,6 +10,7 @@ import function.UserDefinedFunction.IllegalKeywordRestPositionException import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Assertions.assertThrows import org.junit.jupiter.api.Test +import testutil.LispTestInstance import testutil.SymbolAndFunctionCleaner import testutil.TestUtilities.assertSExpressionsMatch import testutil.TestUtilities.evaluateString @@ -17,6 +18,7 @@ import testutil.TestUtilities.parseString import java.io.ByteArrayOutputStream import java.io.PrintStream +@LispTestInstance class DefmacroTest : SymbolAndFunctionCleaner() { private var outputStream = ByteArrayOutputStream() diff --git a/src/test/kotlin/function/builtin/special/DefunTest.kt b/src/test/kotlin/function/builtin/special/DefunTest.kt index 2acd4f8..eed1e4f 100644 --- a/src/test/kotlin/function/builtin/special/DefunTest.kt +++ b/src/test/kotlin/function/builtin/special/DefunTest.kt @@ -10,6 +10,7 @@ import function.UserDefinedFunction.IllegalKeywordRestPositionException import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Assertions.assertThrows import org.junit.jupiter.api.Test +import testutil.LispTestInstance import testutil.SymbolAndFunctionCleaner import testutil.TestUtilities.assertSExpressionsMatch import testutil.TestUtilities.evaluateString @@ -17,6 +18,7 @@ import testutil.TestUtilities.parseString import java.io.ByteArrayOutputStream import java.io.PrintStream +@LispTestInstance class DefunTest : SymbolAndFunctionCleaner() { private var outputStream = ByteArrayOutputStream() diff --git a/src/test/kotlin/function/builtin/special/IFTest.java b/src/test/kotlin/function/builtin/special/IFTest.java deleted file mode 100644 index fe0db53..0000000 --- a/src/test/kotlin/function/builtin/special/IFTest.java +++ /dev/null @@ -1,75 +0,0 @@ -package function.builtin.special; - -import function.ArgumentValidator.TooFewArgumentsException; -import function.ArgumentValidator.TooManyArgumentsException; -import function.builtin.Eval.UndefinedSymbolException; -import org.junit.Test; -import testutil.SymbolAndFunctionCleaner; - -import static testutil.TestUtilities.evaluateString; -import static testutil.TypeAssertions.assertNil; -import static testutil.TypeAssertions.assertT; - -public class IFTest extends SymbolAndFunctionCleaner { - - @Test - public void ifWithOneExpression_ReturnsExpression() { - String input = "(if t t)"; - - assertT(evaluateString(input)); - } - - @Test - public void ifWithOneExpression_ReturnsNil() { - String input = "(if nil t)"; - - assertNil(evaluateString(input)); - } - - @Test - public void ifWithTwoExpressions_ReturnsFirst() { - String input = "(if t t nil)"; - - assertT(evaluateString(input)); - } - - @Test - public void ifWithTwoExpressions_ReturnsSecond() { - String input = "(if nil nil t)"; - - assertT(evaluateString(input)); - } - - @Test - public void ifWithNumericConditional() { - String input = "(if 23 t nil)"; - - assertT(evaluateString(input)); - } - - @Test(expected = UndefinedSymbolException.class) - public void ifWithNilCondition_DoesNotEvaluateThenForm() { - String input = "(if nil (setq x 22))"; - - assertNil(evaluateString(input)); - evaluateString("x"); - } - - @Test(expected = UndefinedSymbolException.class) - public void ifWithTrueCondition_DoesNotEvaluateElseForm() { - String input = "(if t nil (setq x 22))"; - - assertNil(evaluateString(input)); - evaluateString("x"); - } - - @Test(expected = TooFewArgumentsException.class) - public void ifWithTooFewArguments() { - evaluateString("(if t)"); - } - - @Test(expected = TooManyArgumentsException.class) - public void ifWithTooManyArguments() { - evaluateString("(if t t t t)"); - } -} diff --git a/src/test/kotlin/function/builtin/special/IfTest.kt b/src/test/kotlin/function/builtin/special/IfTest.kt new file mode 100644 index 0000000..ea16d12 --- /dev/null +++ b/src/test/kotlin/function/builtin/special/IfTest.kt @@ -0,0 +1,85 @@ +package function.builtin.special + +import function.ArgumentValidator.TooFewArgumentsException +import function.ArgumentValidator.TooManyArgumentsException +import function.builtin.Eval.UndefinedSymbolException +import org.junit.jupiter.api.Assertions.assertThrows +import org.junit.jupiter.api.Test +import testutil.LispTestInstance +import testutil.SymbolAndFunctionCleaner +import testutil.TestUtilities.evaluateString +import testutil.TypeAssertions.assertNil +import testutil.TypeAssertions.assertT + +@LispTestInstance +class IfTest : SymbolAndFunctionCleaner() { + + @Test + fun ifWithOneExpression_ReturnsExpression() { + val input = "(if t t)" + + assertT(evaluateString(input)) + } + + @Test + fun ifWithOneExpression_ReturnsNil() { + val input = "(if nil t)" + + assertNil(evaluateString(input)) + } + + @Test + fun ifWithTwoExpressions_ReturnsFirst() { + val input = "(if t t nil)" + + assertT(evaluateString(input)) + } + + @Test + fun ifWithTwoExpressions_ReturnsSecond() { + val input = "(if nil nil t)" + + assertT(evaluateString(input)) + } + + @Test + fun ifWithNumericConditional() { + val input = "(if 23 t nil)" + + assertT(evaluateString(input)) + } + + @Test + fun ifWithNilCondition_DoesNotEvaluateThenForm() { + val input = "(if nil (setq x 22))" + + assertNil(evaluateString(input)) + assertThrows(UndefinedSymbolException::class.java) { + evaluateString("x") + } + } + + @Test + fun ifWithTrueCondition_DoesNotEvaluateElseForm() { + val input = "(if t nil (setq x 22))" + + assertNil(evaluateString(input)) + assertThrows(UndefinedSymbolException::class.java) { + evaluateString("x") + } + } + + @Test + fun ifWithTooFewArguments() { + assertThrows(TooFewArgumentsException::class.java) { + evaluateString("(if t)") + } + } + + @Test + fun ifWithTooManyArguments() { + assertThrows(TooManyArgumentsException::class.java) { + evaluateString("(if t t t t)") + } + } +} diff --git a/src/test/kotlin/function/builtin/special/PROGNTest.java b/src/test/kotlin/function/builtin/special/PROGNTest.java deleted file mode 100644 index ff02fc7..0000000 --- a/src/test/kotlin/function/builtin/special/PROGNTest.java +++ /dev/null @@ -1,42 +0,0 @@ -package function.builtin.special; - -import org.junit.Test; -import testutil.SymbolAndFunctionCleaner; - -import static testutil.TestUtilities.assertSExpressionsMatch; -import static testutil.TestUtilities.evaluateString; -import static testutil.TestUtilities.parseString; -import static testutil.TypeAssertions.assertNil; - -public class PROGNTest extends SymbolAndFunctionCleaner { - - @Test - public void prognWithNoArguments() { - assertNil(evaluateString("(progn)")); - } - - @Test - public void prognWithOneArgument() { - assertSExpressionsMatch(parseString("1"), evaluateString("(progn 1)")); - } - - @Test - public void prognWithSeveralArguments() { - assertSExpressionsMatch(parseString("5"), evaluateString("(progn 1 2 3 4 5)")); - } - - @Test - public void beginWithSeveralArguments() { - assertSExpressionsMatch(parseString("5"), evaluateString("(begin 1 2 3 4 5)")); - } - - @Test - public void prognEvaluatesArgument() { - assertSExpressionsMatch(parseString("1"), evaluateString("(progn (car '(1 2 3)))")); - } - - @Test - public void prognWithDifferentArgumentTypes() { - assertSExpressionsMatch(parseString("pear"), evaluateString("(progn t nil '(1 2) 'pear)")); - } -} diff --git a/src/test/kotlin/function/builtin/special/QUOTETest.java b/src/test/kotlin/function/builtin/special/QUOTETest.java deleted file mode 100644 index 9092414..0000000 --- a/src/test/kotlin/function/builtin/special/QUOTETest.java +++ /dev/null @@ -1,37 +0,0 @@ -package function.builtin.special; - -import function.ArgumentValidator.TooFewArgumentsException; -import function.ArgumentValidator.TooManyArgumentsException; -import org.junit.Test; -import testutil.SymbolAndFunctionCleaner; - -import static testutil.TestUtilities.assertSExpressionsMatch; -import static testutil.TestUtilities.evaluateString; -import static testutil.TestUtilities.parseString; - -public class QUOTETest extends SymbolAndFunctionCleaner { - - @Test - public void quoteSymbol() { - String input = "'a"; - - assertSExpressionsMatch(parseString("a"), evaluateString(input)); - } - - @Test - public void quoteList() { - String input = "'(l i s t)"; - - assertSExpressionsMatch(parseString("(l i s t)"), evaluateString(input)); - } - - @Test(expected = TooFewArgumentsException.class) - public void quoteWithTooFewArguments() { - evaluateString("(quote)"); - } - - @Test(expected = TooManyArgumentsException.class) - public void quoteWithTooManyArguments() { - evaluateString("(quote a b)"); - } -} diff --git a/src/test/kotlin/function/builtin/special/QuoteTest.kt b/src/test/kotlin/function/builtin/special/QuoteTest.kt new file mode 100644 index 0000000..d369b86 --- /dev/null +++ b/src/test/kotlin/function/builtin/special/QuoteTest.kt @@ -0,0 +1,43 @@ +package function.builtin.special + +import function.ArgumentValidator.TooFewArgumentsException +import function.ArgumentValidator.TooManyArgumentsException +import org.junit.jupiter.api.Assertions.assertThrows +import org.junit.jupiter.api.Test +import testutil.LispTestInstance +import testutil.SymbolAndFunctionCleaner +import testutil.TestUtilities.assertSExpressionsMatch +import testutil.TestUtilities.evaluateString +import testutil.TestUtilities.parseString + +@LispTestInstance +class QuoteTest : SymbolAndFunctionCleaner() { + + @Test + fun quoteSymbol() { + val input = "'a" + + assertSExpressionsMatch(parseString("a"), evaluateString(input)) + } + + @Test + fun quoteList() { + val input = "'(l i s t)" + + assertSExpressionsMatch(parseString("(l i s t)"), evaluateString(input)) + } + + @Test + fun quoteWithTooFewArguments() { + assertThrows(TooFewArgumentsException::class.java) { + evaluateString("(quote)") + } + } + + @Test + fun quoteWithTooManyArguments() { + assertThrows(TooManyArgumentsException::class.java) { + evaluateString("(quote a b)") + } + } +}