transcendental-lisp/src/main/kotlin/function/builtin/cons/Append.kt
2018-11-10 08:30:15 -05:00

64 lines
1.7 KiB
Kotlin

package function.builtin.cons
import function.ArgumentValidator
import function.FunctionNames
import function.LispFunction
import sexpression.Cons
import sexpression.Nil
import table.FunctionTable.lookupFunction
@FunctionNames("APPEND")
class Append(name: String) : LispFunction() {
private val argumentValidator = ArgumentValidator(name).apply {
setExactNumberOfArguments(2)
setEveryArgumentExpectedType(Cons::class.java)
}
private val firstListValidator = ArgumentValidator("$name|first-list|")
override fun call(argumentList: Cons): Cons {
argumentValidator.validate(argumentList)
val rest = argumentList.rest as Cons
val firstList = argumentList.first as Cons
val secondList = rest.first as Cons
return appendLists(firstList, secondList)
}
private fun appendLists(firstList: Cons, secondList: Cons): Cons {
firstListValidator.validate(firstList)
if (firstList.isNull)
return secondList
val appendedLists = copy(firstList)
appendedLists.last().rest = secondList
return appendedLists
}
private fun copy(list: Cons): Cons {
val newList = Cons(list.first, Nil)
var builder = newList
list.asSequence().drop(1).forEach {
builder.rest = Cons(it.first, Nil)
builder = builder.rest as Cons
}
return newList
}
companion object {
@JvmStatic
fun append(firstList: Cons, secondList: Cons): Cons {
return lookupAppend().appendLists(firstList, secondList)
}
private fun lookupAppend() = lookupFunction("APPEND") as Append
}
}