!7 static Map> theSet; static new HashSet allObjects; sclass Updatable { void update {} } sclass Expectation { S ifClass; Runnable action; *() {} *(S *ifClass, Runnable *action) {} } sclass Word extends Updatable { S text; // or null if unknown Word prev, next; L constituents; // if group new Set expectations; new Set fulfilledExpectations; new Set classes; new Set groups; // I am part of void update { // Add direct word classes if (text != null) classes.addAll(reverseLookupInMapToSets(theSet, text)); // Make text for group if (isGroup() && text == null) { L l = collect(constituents, 'text); if (!anyNull(l)) text = joinWithSpace(l); } // Process expectations for (Expectation e : cloneList(expectations)) if (classes.contains(e.ifClass)) { moveElementFromCollectionToCollection(e, expectations, fulfilledExpectations); callF(e.action); } } bool isGroup() { ret constituents != null; } void addExpectation(Expectation e) { print("addExpectation " + e); expectations.add(e); } } static Word makeGroup(Word a, Word b) { L list = ll(a, b); // look for existing group for (Word g : a.groups) if (eq(g.constituents, list)) ret g; // new group new Word g; allObjects.add(g); g.constituents = list; for (Word w : list) w.groups.add(g); ret g; } sclass The extends Word { bool expectationSentToNext; void update { super.update(); if (next != null && !expectationSentToNext) { final Word _next = next; _next.addExpectation(Expectation("", r { makeGroup(The.this, _next).classes.add(""); })); set expectationSentToNext; } } } p-exp { S sentence = "In the movies Dracula always wears a cape"; L rawWords = printStruct(words(sentence)); theSet = ai_englishWordCategoriesWithElements(); new L words; for (S w : rawWords) words.add(nu(eqic(w, "the") ? The : Word, text := w)); for (int i = 0; i < l(words)-1; i++) linkWords(words.get(i), words.get(i+1)); //printStruct(first(words)); addAll(allObjects, words); S struct = struct(first(words)), lastStruct; do { print("l(struct)=" + l(struct)); for (Updatable w : cloneList(allObjects)) w.update(); lastStruct = struct; } while (eq(lastStruct, struct = struct(first(words)))); for (Word w : words) printStruct(cloneForPrinting(w)); L groups = [Word w : instancesOf(Word, allObjects) | w.constituents != null]; print(n2(groups, "group")); for (Word g : groups) print("Group: " + cloneForPrinting(g)); } svoid linkWords(Word a, Word b) { a.next = b; b.prev = a; } static O cloneForPrinting(Word w) { ret cloneWithoutFields(w, 'prev, 'next, 'constituents); }