!752 answer { if (!attn()) ret null; s = s.trim(); if (s.startsWith("snl ")) exceptionToUser { S input = dropPrefix("snl ", s).trim(); Explain e = snlParse(input); if (e == null) ret "No parse"; //L classes = getClasses(e); //ret "Top classes: " + structure(classes); L parts = topParts(e); L topOperators = getOperators(parts); ret "Top parts: " + structure(mapString(parts)) + ". Top operators: " + structure(topOperators); } } static L mapString(L e) { new L l; for (Explain ex : e) l.add(ex == null ? "null" : ex.string()); ret l; } static L topParts(Explain e) { if (e == null) ret litlist(); L classes = getClasses(e); //ret "Classes: " + structure(classes); if (classes.contains("juxta")) { Explain juxta = descend(e, "juxta"); L parts = scanJuxta(juxta); if (allAre(parts, "subword")) // sentences! ret topParts(parts); else ret litlist(juxta); // it's actually one sentence } /*else if (classes.contains("subword")) ret descend(e, "subword");*/ else ret litlist(e); // just return whatever we have as a top part } static L topParts(L list) { new L l; for (Explain e : list) l.addAll(topParts(e)); ret l; } static L scanJuxta(Explain e) { if (isA(e, "juxta")) { Explain juxta = descend(e, "juxta"); Explain a = juxta.sub(0), b = juxta.sub(1); ret concatLists(scanJuxta(a), scanJuxta(b)); } else ret litlist(e); } static L getClasses(Explain e) { new L l; while (e != null) { l.add(e.className()); if (l(e.subs) == 1) e = e.sub(0); else break; } ret l; } static Explain castTo(Explain e, S className) { ret descend(e, className); } static Explain descend(Explain e, S className) { new L l; while (e != null) { if (eq(e.className(), className)) ret e; if (l(e.subs) == 1) e = e.sub(0); else break; } ret null; } static boolean isA(Explain e, S className) { ret getClasses(e).contains(className); } static boolean allAre(L l, S className) { for (Explain e: l) if (!isA(e, className)) ret false; ret true; } static boolean anyAre(L l, S className) { for (Explain e: l) if (isA(e, className)) ret true; ret false; } static L getOperators(L parts) { new L l; for (Explain e : parts) l.add(makeOperator(e)); ret l; } static S makeOperatorFromJuxta(L parts) { new L l; int i = 0; for (Explain e : parts) { //print("Operator part " + (++i) + ": " + e.string() + " / " + structure(getClasses(e))); if (!isA(e, "subword") && isA(e, "idword")) l.add(e.string()); else l.add("*"); } ret join(" ", l); } static L getJuxtaArgs(L parts) { new L l; int i = 0; for (Explain e : parts) if (!isA(e, "subword") && isA(e, "idword")) { // operator part, skip } else l.add(e); ret l; } static S makeOperator(Explain e) { if (isA(e, "realarrow")) ret descend(e, "realarrow").sub(0).string() + " *"; else if (isA(e, "juxta")) { L j = scanJuxta(e); //print("scanJuxta => " + structure(j)); ret makeOperatorFromJuxta(j); } else ret e.string(); } static Lisp getTree(Explain e) { print("getTree " + structure(getClasses(e))); if (isA(e, "realarrow")) { print("realarrow"); Explain a = castTo(e, "realarrow"); ret lisp("<", getTree(a.sub(0)), getTree(a.sub(1))); } if (isA(e, "realarrowr")) { print("realarrowr"); Explain a = castTo(e, "realarrowr"); ret lisp(">", getTree(a.sub(0)), getTree(a.sub(1))); } if (isA(e, "square")) { print("square"); Explain a = castTo(e, "square"); ret lisp("[]", getTree(a.sub(0))); } if (isA(e, "round")) { Explain a = castTo(e, "round"); ret lisp("()", getTree(a.sub(0))); } if (isA(e, "juxta")) { Explain juxta = descend(e, "juxta"); L parts = scanJuxta(juxta); print("juxta " + e.string()); if (anyAre(parts, "subword")) { L args = getJuxtaArgs(parts); Lisp l = lisp(makeOperatorFromJuxta(parts)); for (Explain arg : args) l.add(removeBrackets(getTree(arg))); ret l; } print(" no subwords"); // no subwords, fall back to simple string } ret lisp(e.string()); } static Lisp removeBrackets(Lisp l) { if (eq(l.head, "[]")) ret l.get(0); ret l; }