From bfc8ccd25ff9b611d5433a0ed08f4df6c0eb38b1 Mon Sep 17 00:00:00 2001 From: Mike Cifelli <1836280-mike-cifelli@users.noreply.gitlab.com> Date: Thu, 18 Jul 2019 19:29:05 -0400 Subject: [PATCH] Refactor mutual tail call code --- .../recursion/{TailCall.kt => MutualTailCall.kt} | 8 ++++---- src/main/kotlin/recursion/MutualTailCalls.kt | 14 ++++++++++++++ src/main/kotlin/recursion/TailCalls.kt | 14 -------------- src/main/kotlin/sexpression/Cons.kt | 14 +++++++------- src/main/kotlin/token/RightParenthesis.kt | 12 ++++++------ src/main/kotlin/token/Token.kt | 12 ++++++------ .../{TailCallTest.kt => MutualTailCallTest.kt} | 10 +++++----- 7 files changed, 42 insertions(+), 42 deletions(-) rename src/main/kotlin/recursion/{TailCall.kt => MutualTailCall.kt} (56%) create mode 100644 src/main/kotlin/recursion/MutualTailCalls.kt delete mode 100644 src/main/kotlin/recursion/TailCalls.kt rename src/test/kotlin/recursion/{TailCallTest.kt => MutualTailCallTest.kt} (66%) diff --git a/src/main/kotlin/recursion/TailCall.kt b/src/main/kotlin/recursion/MutualTailCall.kt similarity index 56% rename from src/main/kotlin/recursion/TailCall.kt rename to src/main/kotlin/recursion/MutualTailCall.kt index 4442cfe..72b9b8c 100644 --- a/src/main/kotlin/recursion/TailCall.kt +++ b/src/main/kotlin/recursion/MutualTailCall.kt @@ -1,12 +1,12 @@ package recursion -interface TailCall { +interface MutualTailCall { - fun isComplete() = false - fun apply(): TailCall + fun isTerminal() = false + fun apply(): MutualTailCall fun result(): T = throw UnsupportedOperationException() operator fun invoke() = generateSequence(this) { it.apply() } - .first { it.isComplete() } + .first { it.isTerminal() } .result() } diff --git a/src/main/kotlin/recursion/MutualTailCalls.kt b/src/main/kotlin/recursion/MutualTailCalls.kt new file mode 100644 index 0000000..ac50253 --- /dev/null +++ b/src/main/kotlin/recursion/MutualTailCalls.kt @@ -0,0 +1,14 @@ +package recursion + +object MutualTailCalls { + + fun recursiveCall(nextCall: () -> MutualTailCall) = object : MutualTailCall { + override fun apply() = nextCall() + } + + fun terminalValue(value: T) = object : MutualTailCall { + override fun isTerminal() = true + override fun result() = value + override fun apply() = throw UnsupportedOperationException() + } +} \ No newline at end of file diff --git a/src/main/kotlin/recursion/TailCalls.kt b/src/main/kotlin/recursion/TailCalls.kt deleted file mode 100644 index 3e24c2d..0000000 --- a/src/main/kotlin/recursion/TailCalls.kt +++ /dev/null @@ -1,14 +0,0 @@ -package recursion - -object TailCalls { - - fun tailCall(nextCall: () -> TailCall) = object : TailCall { - override fun apply() = nextCall() - } - - fun done(value: T) = object : TailCall { - override fun isComplete() = true - override fun result() = value - override fun apply() = throw UnsupportedOperationException() - } -} \ No newline at end of file diff --git a/src/main/kotlin/sexpression/Cons.kt b/src/main/kotlin/sexpression/Cons.kt index a0b06a2..6dfbd62 100644 --- a/src/main/kotlin/sexpression/Cons.kt +++ b/src/main/kotlin/sexpression/Cons.kt @@ -1,9 +1,9 @@ package sexpression -import recursion.TailCall +import recursion.MutualTailCall -import recursion.TailCalls.done -import recursion.TailCalls.tailCall +import recursion.MutualTailCalls.terminalValue +import recursion.MutualTailCalls.recursiveCall @DisplayName("list") open class Cons(open var first: SExpression, open var rest: SExpression) : SExpression(), Iterable { @@ -14,16 +14,16 @@ open class Cons(open var first: SExpression, open var rest: SExpression) : SExpr return toStringTailRecursive(StringBuilder("(")).invoke() } - private fun toStringTailRecursive(leadingString: StringBuilder): TailCall { + private fun toStringTailRecursive(leadingString: StringBuilder): MutualTailCall { leadingString.append(first.toString()) if (rest.isNull) - return done(leadingString.append(")").toString()) + return terminalValue(leadingString.append(")").toString()) else if (rest.isCons) { - return tailCall { (rest as Cons).toStringTailRecursive(leadingString.append(" ")) } + return recursiveCall { (rest as Cons).toStringTailRecursive(leadingString.append(" ")) } } - return done(leadingString.append(" . " + rest.toString() + ")").toString()) + return terminalValue(leadingString.append(" . $rest)").toString()) } override fun iterator(): Iterator = ConsIterator(this) diff --git a/src/main/kotlin/token/RightParenthesis.kt b/src/main/kotlin/token/RightParenthesis.kt index 3c9c0b7..6dd022e 100644 --- a/src/main/kotlin/token/RightParenthesis.kt +++ b/src/main/kotlin/token/RightParenthesis.kt @@ -2,8 +2,8 @@ package token import error.LineColumnException import file.FilePosition -import recursion.TailCall -import recursion.TailCalls.done +import recursion.MutualTailCall +import recursion.MutualTailCalls.terminalValue import sexpression.Cons import sexpression.Nil import sexpression.SExpression @@ -14,12 +14,12 @@ class RightParenthesis(text: String, position: FilePosition) : Token(text, posit throw StartsWithRightParenthesisException(position) } - override fun parseListTail(getNextToken: () -> Token): TailCall { - return done(Nil) + override fun parseListTail(getNextToken: () -> Token): MutualTailCall { + return terminalValue(Nil) } - override fun parseListTailRecursive(start: Cons, end: Cons, getNextToken: () -> Token): TailCall { - return done(start) + override fun parseListTailRecursive(start: Cons, end: Cons, getNextToken: () -> Token): MutualTailCall { + return terminalValue(start) } class StartsWithRightParenthesisException(position: FilePosition) : LineColumnException(position) { diff --git a/src/main/kotlin/token/Token.kt b/src/main/kotlin/token/Token.kt index c1f8708..4a29ef3 100644 --- a/src/main/kotlin/token/Token.kt +++ b/src/main/kotlin/token/Token.kt @@ -1,8 +1,8 @@ package token import file.FilePosition -import recursion.TailCall -import recursion.TailCalls.tailCall +import recursion.MutualTailCall +import recursion.MutualTailCalls.recursiveCall import sexpression.Cons import sexpression.Nil import sexpression.SExpression @@ -19,18 +19,18 @@ abstract class Token(val text: String, val position: FilePosition) { abstract fun parseSExpression(getNextToken: () -> Token): SExpression - open fun parseListTail(getNextToken: () -> Token): TailCall { + open fun parseListTail(getNextToken: () -> Token): MutualTailCall { val firstCons = Cons(parseSExpression(getNextToken), Nil) val next = getNextToken() - return tailCall { next.parseListTailRecursive(firstCons, firstCons, getNextToken) } + return recursiveCall { next.parseListTailRecursive(firstCons, firstCons, getNextToken) } } - protected open fun parseListTailRecursive(start: Cons, end: Cons, getNextToken: () -> Token): TailCall { + protected open fun parseListTailRecursive(start: Cons, end: Cons, getNextToken: () -> Token): MutualTailCall { val newEnd = Cons(parseSExpression(getNextToken), Nil) val next = getNextToken() end.rest = newEnd - return tailCall { next.parseListTailRecursive(start, newEnd, getNextToken) } + return recursiveCall { next.parseListTailRecursive(start, newEnd, getNextToken) } } } diff --git a/src/test/kotlin/recursion/TailCallTest.kt b/src/test/kotlin/recursion/MutualTailCallTest.kt similarity index 66% rename from src/test/kotlin/recursion/TailCallTest.kt rename to src/test/kotlin/recursion/MutualTailCallTest.kt index f5c6316..7c2c23d 100644 --- a/src/test/kotlin/recursion/TailCallTest.kt +++ b/src/test/kotlin/recursion/MutualTailCallTest.kt @@ -2,16 +2,16 @@ package recursion import org.junit.jupiter.api.Assertions.assertThrows import org.junit.jupiter.api.Test -import recursion.TailCalls.done +import recursion.MutualTailCalls.terminalValue import testutil.LispTestInstance @LispTestInstance -class TailCallTest { +class MutualTailCallTest { @Test fun `tailCall does not support result`() { - val tailCall = object : TailCall { - override fun apply() = done(null) + val tailCall = object : MutualTailCall { + override fun apply() = terminalValue(null) } assertThrows(UnsupportedOperationException::class.java) { tailCall.result() } @@ -19,6 +19,6 @@ class TailCallTest { @Test fun `done does not support apply`() { - assertThrows(UnsupportedOperationException::class.java) { done(null).apply() } + assertThrows(UnsupportedOperationException::class.java) { terminalValue(null).apply() } } }