// a Lisp-like form static class Lisp implements Iterable { S head; new L args; *() {} *(S *head) {} public S toString() { if (args.isEmpty()) return quoteIfNotIdentifier(head); new L bla; for (Lisp a : args) bla.add(a.toString()); S inner = join(", ", bla); if (head.equals("")) return "{" + inner + "}"; // list else return quoteIfNotIdentifier(head) + "(" + inner + ")"; } void add(Lisp l) { args.add(l); } void add(S s) { args.add(new Lisp(s)); } int size() { return args.size(); } boolean isEmpty() { return args.isEmpty(); } Lisp get(int i) { return args.get(i); } S getString(int i) { return get(i).head; } S s(int i) { return getString(i); } boolean is(S... heads) { return asList(heads).contains(head); } public Iterator iterator() { return args.iterator(); } Lisp subList(int fromIndex, int toIndex) { Lisp l = new Lisp(head); l.args.addAll(args.subList(fromIndex, toIndex)); // better to copy here I guess - safe return l; } } // make a lisp form static Lisp lisp(S head, Object... args) { Lisp l = new Lisp(head); for (O o : args) if (o instanceof String) l.args.add(new Lisp((String) o)); else if (o instanceof Lisp) l.args.add((Lisp) o); else fail("Bad argument type: " + o); return l; } static Lisp lisplist(O... x) { return lisp("", x); } static Lisp enter(O... x) { return lisp("enter", x); } static Lisp answer(O... x) { return lisp("answer", x); } static Lisp or(O... x) { return lisp("or", x); }