!7 sS verbs = toLinesFullTrim([[ kow towed made started want ]]); sclass StringTree { new HashMap children; StringTree getOrAdd(S s) { StringTree t = children.get(s); if (t == null) children.put(s, t = new StringTree); ret t; } } static Map map; // value = another map of the same kind p { map = multiWordMap_lower(verbs); callAnswerFunctionVerbose("he kow towed before them"); callAnswerFunctionVerbose("i want stuff"); botSleep(); } static StringTree multiWordMap_lower(S items) { new StringTree tree; for (S s : items) { L tok = codeTokens(nlTok4(lower(s))); addToTree(tree, tok); } ret tree; } svoid addToTree(StringTree tree, L tok) { if (empty(tok)) ret; S s = first(tok); StringTree t = tree.getOrAdd(s); addToTree(t, dropFirst(tok)); } sS answer(S s) { for L tok = codeTokens(nlTok4(s))); ret group(s); } sS group(S s) { s = groupStep(s); L tok = joinBrackets(javaTok(s)); for (int i = 1; i < l(tok); i += 2) { S t = tok.get(i); if (isRoundBracketed(t)) tok.set(i, "(" + group(dropFirstAndLast(t)) + ")"); } ret join(tok); } sS groupStep(S s) { L tok = codeTokens(dropPunctuation(javaTok(s))); TokConsumer c = new(tok); S verb = consumeVerb(c); if (verb != null) { S noun = consumeNoun(c); if (noun != null) ret group(verb, noun, rest(c)); } ret joinWithSpace(tok); } static Set verbs = asSet(splitAtSpace("can does will tell would were do")); static Set nouns = asSet(splitAtSpace("i you he she it we someone me")); static S consumeVerb(TokConsumer c) { ret consumeFromList(verbs, c); } static S consumeNoun(TokConsumer c) { ret consumeFromList(nouns, c); } static S consumeFromList(Set set, TokConsumer c) { if (set.contains(toLower(c.peek()))) ret c.next(); null; } sS group(S... parts) { new L l; for (S part : parts) { L tok = javaTokC(part); if (l(tok) > 1) l.add("(" + joinWithSpace(tok) + ")"); else l.addAll(tok); } ret joinWithSpace(l); } sS rest(TokConsumer c) { ret joinWithSpace(c.remainingTokens()); }