!7 sclass ApplySF { S name; int pos; L args; *() {} *(S *name, int *pos, O... args) { this.args = asList(args); } O call(O o) { L args = cloneList(this.args); args.add(pos, o); ret makeAndCall(name, toObjectArray(args)); } } sclass Operation { ApplySF op; Data result; *() {} *(ApplySF *op) {} } sclass Data { O data; bool error; new L operations; *() {} *(O *data) {} } static Data initial; p-tt { S input = loadSnippet(#1008462); initial = new Data(input); doOp(initial, new ApplySF("findSubstringsEnclosedBy_inner", 0, '<', '>')); printTree("", initial); } svoid printTree(Data data) { if (data == null) { print("-"); ret; } if (data.error) print("Error"); else print("Data: " + shorten(struct(data.data))); print_threadIndentPlus(); try { int i = 0; for (Operation op : data.operations) { print("Op " + (++i) + ": " + struct(op.op)); printTree(op.result); } } finally { print_threadIndentMinus(); } } svoid doOp(Data data, ApplySF theOp) { Operation op = new Operation(theOp); data.operations.add(op); try { op.result = new Data(op.op.call(data.data)); } catch { op.result = nu(Data, error := true); } }