transcendental-lisp/src/main/function/builtin/cons/APPEND.java

76 lines
2.1 KiB
Java

package function.builtin.cons;
import static sexpression.Nil.NIL;
import static table.FunctionTable.lookupFunction;
import function.ArgumentValidator;
import function.FunctionNames;
import function.LispFunction;
import sexpression.Cons;
@FunctionNames({ "APPEND" })
public class APPEND extends LispFunction {
public static Cons append(Cons firstList, Cons secondList) {
return lookupAppend().appendLists(firstList, secondList);
}
private static APPEND lookupAppend() {
return (APPEND) lookupFunction("APPEND");
}
private ArgumentValidator argumentValidator;
private ArgumentValidator firstListValidator;
public APPEND(String name) {
this.argumentValidator = new ArgumentValidator(name);
this.argumentValidator.setExactNumberOfArguments(2);
this.argumentValidator.setEveryArgumentExpectedType(Cons.class);
this.firstListValidator = new ArgumentValidator(name + "|first-list|");
}
@Override
public Cons call(Cons argumentList) {
argumentValidator.validate(argumentList);
Cons rest = (Cons) argumentList.getRest();
Cons firstList = (Cons) argumentList.getFirst();
Cons secondList = (Cons) rest.getFirst();
return appendLists(firstList, secondList);
}
private Cons appendLists(Cons firstList, Cons secondList) {
firstListValidator.validate(firstList);
if (firstList.isNull())
return secondList;
Cons appendedLists = copy(firstList);
getLastItem(appendedLists).setRest(secondList);
return appendedLists;
}
private Cons copy(Cons list) {
Cons newList = new Cons(list.getFirst(), NIL);
Cons builder = newList;
for (Cons iterator = (Cons) list.getRest(); iterator.isCons(); iterator = (Cons) iterator.getRest()) {
builder.setRest(new Cons(iterator.getFirst(), NIL));
builder = (Cons) builder.getRest();
}
return newList;
}
private Cons getLastItem(Cons list) {
Cons tail = list;
while (tail.getRest().isCons())
tail = (Cons) tail.getRest();
return tail;
}
}