/* event change; => transient LinkedHashSet onChange; public selfType onChange(Runnable r) { onChange = syncAddOrCreate(onChange, r); this; } void change() { if (onChange != null) for (listener : onChange) pcallF_typed(listener); } ; } */ svoid tok_eventFunctions(LS tok) { int i; while ((i = jfind(tok, "event ", nIdx -> !eqGet(tok, nIdx+3, "aka"))) >= 0) { int iModifiers = tok_leftScanModifiers(tok, i); S modifiers = joinSubList(tok, iModifiers, i-1); int iSemicolon = i+4; LS tokArgs = null; if (eqGet(tok, i+4, "(")) { int argsFrom = i+6; int argsTo = findCodeTokens(tok, argsFrom, false, ")"); tokArgs = subList(tok, argsFrom-1, argsTo); iSemicolon = argsTo+2; } int iEnd = iSemicolon+1; S body = ""; if (eqGet(tok, iSemicolon, "{")) { iEnd = tok_findEndOfBlock(tok, iSemicolon); body = joinSubList(tok, iSemicolon+1, iEnd-1); } else if (neqGet(tok, iSemicolon, ";")) fail("Semicolon expected at end: " + joinSubList(tok, i, iSemicolon+1)); S change = tok.get(i+2), prefix = ""; if (startsWithCamelCaseWord(change, "on")) change = firstToLower(dropFirst(2, change)); else if (startsWithCamelCaseWord(change, "fire")) { prefix = "fire"; change = firstToLower(dropFirst(4, change)); } S onChange = "on" + firstToUpper(change); S removeListener = "remove" + firstToUpper(change) + "Listener"; LPairS args = tok_typesAndNamesOfParams(tokArgs); LS types = pairsA(args); S args1 = join(dropFirstAndLast(tokArgs)); S args2 = joinWithComma(pairsB(args)); S typeParams = joinWithComma(map tok_toNonPrimitiveTypes(types)); S listenerType = empty(args) ? "Runnable" : "IVF" + l(args) + "<" + typeParams + ">"; S r = empty(args) ? "r" : "f"; S fireChange = empty(prefix) ? change : prefix + firstToUpper(change); replaceTokens_reTok(tok, iModifiers, iEnd, "\*modifiers*/ transient Set<\*listenerType*/> \*onChange*/;\n" + "public \*modifiers*/ selfType \*onChange*/(\*listenerType*/ \*r*/) { \*onChange*/ = createOrAddToSyncLinkedHashSet(\*onChange*/, \*r*/); this; }\n" + "public \*modifiers*/ selfType \*removeListener*/(\*listenerType*/ \*r*/) { main remove(\*onChange*/, \*r*/); this; }\n" + "public \*modifiers*/ void \*fireChange*/(\*args1*/) { \*body*/ " + "if (\*onChange*/ != null) for (listener : \*onChange*/) " + "pcallF_typed(" + joinNemptiesWithComma("listener", args2) + "); " + "}" ); } }