package serene.simple; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.function.Function; import static java.util.Arrays.asList; public class ListNode extends Node implements Iterable { public static final ListNode EMPTY = new ListNode<>(); public final T first; public final ListNode rest; public final int length; public ListNode() { this.first = null; this.rest = null; this.length = 0; } public ListNode(T f, ListNode r) { this.first = f; this.rest = r; this.length = r.length + 1; } @SafeVarargs public static ListNode list(T... objs) { return list(asList(objs)); } public static ListNode list(List objs) { ListNode l = (ListNode) EMPTY; for (int i = objs.size() - 1; i >= 0; i--) { l = l.cons(objs.get(i)); } return l; } public ListNode cons(T node) { return new ListNode(node, this); } @Override public Object eval(Scope scope) { Function f = (Function) this.first.eval(scope); List args = new ArrayList(); for (T node : this.rest) { args.add(node.eval(scope)); } return f.apply(args.toArray()); } public T first() { if (this != EMPTY) { return this.first; } return null; } public ListNode rest() { if (this != EMPTY) { return this.rest; } return (ListNode) EMPTY; } @Override public Iterator iterator() { return new Iterator() { private ListNode l = ListNode.this; @Override public boolean hasNext() { return this.l != EMPTY; } @Override public T next() { if (this.l == EMPTY) { return null; } T first = this.l.first; this.l = this.l.rest; return first; } @Override public void remove() { throw new SereneException("Iterator is immutable"); } }; } }