// transformer can return null or input on no change // will not call transformer on individual words // returns null if no change static WithTrail lambdaMapLike gazelle_deepTransform_withTrail(IF1> transformer, S input, O... _) { if (transformer == null) null; // call transformer on whole input, return if change WithTrail transformed = transformer.get(input); if (transformed != null) ret transformed; // transformer didn't do anything, tokenize & go through parts O tokenizer = optPar tokenizer(_, f javaTokWithBrackets); LS tok = callTokenizer(tokenizer, input); new L trails; bool changes; for ping (int i = 1; i < l(tok); i += 2) { S t = tok.get(i); if (tok_isRoundOrCurlyBracketed(t)) { S unBracketed = tok_deRoundOrCurlyBracket(t); transformed = gazelle_deepTransform_withTrail(transformer, unBracketed, _); if (transformed != null) { if (!changes) tok = cloneList(tok); // in case a caching tokenizer was used // enclose in brackets & replace tok.set(i, startsWith(t, "(") ? roundOpt(transformed!) : curlyOpt(transformed!)); trails.add(transformed.trail); set changes; } } } ret changes ? WithTrail(litmap(op := "gazelle_deepTransform_withTrail", +input, +trails), join(tok)) : null; }