// parser explainer static class Explain { static L primitiveClasses = litlist("quoted", "identifier", "any", "int"); O parseResult; L tok; L e; new L subs; // XXX - applies to full parse always L fullMatchClasses() { ret (L) call(parseResult, "fullMatchClasses"); } static boolean debug; *(O *parseResult, L *e) { tok = (L) get(parseResult, "tok"); _makeSubExplains(); } void _makeSubExplains() { for (int i = 4; i < l(e); i++) { L sub = cast get(e, i); int t1 = (int) get(sub, 0); int t2 = (int) get(sub, 1); S className = getString(sub, 2); L subE = sub; if (debug) print("subE first = " + sfu(subE)); if (!primitiveClasses.contains(className)) subE = (L) call(parseResult, "explainFull", t1, t2, className); if (debug) printF("Explaining for " + className() + ": * * * => *", t1, t2, className, subE); if (subE == null) subs.add(null); else subs.add(new Explain(parseResult, subE)); } } S className() { ret getString(e, 2); } int fromToken() { ret (int) get(e, 0); } int toToken() { ret (int) get(e, 1); } // return tokens, padded with empty non-code tokens first and last // to make actual CNC L tok() { ret concatLists( litlist(""), subList(tok, fromToken(), toToken()-1), litlist("")); } S string() { ret join(subList(tok, fromToken(), toToken()-1)); } boolean containsToken(S t) { ret main containsToken(tok(), t); } void findAll(S className, L out) { if (eq(className, className())) out.add(string()); else // << this is new - don't recurse for (Explain e : subs) if (e != null) e.findAll(className, out); } L findAll(S className) { new L l; findAll(className, l); ret l; } // short for findFirst Explain find(S className) { ret findFirst(className); } Explain findFirst(S className) { if (eq(className, className())) ret this; ret findFirstSub(className); } // find class, but exclude myself Explain findFirstSub(S className) { for (Explain e : subs) if (e != null) { Explain result = e.findFirst(className); if (result != null) ret result; } ret null; } boolean is(S className) { ret eq(className(), className); } boolean has(S className) { ret findFirst(className) != null; } boolean hasSub(S className) { ret findFirstSub(className) != null; } void findAll2(S className, L out) { if (is(className)) out.add(this); for (Explain e : subs) if (e != null) e.findAll2(className, out); } L findAll2(S className) { new L l; findAll2(className, l); ret l; } // short for pruneSubs Explain prune(S className) { ret pruneSubs(className); } // returns self after pruning Explain pruneSubs(S className) { for (int i = 0; i < l(subs); ) { Explain e = sub(i); if (e == null) ++i; else if (eq(e.className(), className)) subs.remove(i); else { e.pruneSubs(className); ++i; } } ret this; } Explain sub(int i) { ret get(subs, i); } S str(int i) { // ret sub(i).string(); // sub might be null L sub = cast get(e, 4+i); int t1 = (int) get(sub, 0); int t2 = (int) get(sub, 1); ret join(subList(tok, t1, t2-1)); } L subs() { ret subs; } bool singleEqualChild() { if (l(subs) != 1 || first(subs) == null) false; Explain e = first(subs); ret fromToken() == e.fromToken() && toToken() == e.toToken(); } S prettierAnalysis() { ret (S) call(parseResult, "prettierAnalysis"); } }