abstract sclass CTNode { new LinkedHashSet children; toString { ret shortClassName(this) + ": " + toString2(); } abstract S toString2(); bool add(CTNode n) { ret children.add(n); } } sclass TextNode > CTNode { S text; *() {} *(S *text) {} S toString2() { ret quote(text); } } sclass TokNode > CTNode { L tok; *() {} *(LS *tok) {} S toString2() { ret sfu(tok); } public bool equals(O o) { ret stdEq(this, o, 'tok); } public int hashCode() { ret stdHash(this, 'tok); } } sclass ObjectNode > CTNode { O obj; *() {} *(O *obj) {} S toString2() { ret sfu(obj); } public bool equals(O o) { ret stdEq(this, o, 'obj); } public int hashCode() { ret stdHash(this, 'obj); } } sclass OpNode > CTNode { S op; bool haveResult; O result; // this is the result coming back up from the operation *() {} *(S *op) {} S toString2() { ret haveResult ? result + " <- " + op : op; } public bool equals(O o) { ret stdEq(this, o, 'op); } public int hashCode() { ret stdHash(this, 'op); } void setResult(O o) { result = o; haveResult = true; } }