public AST <Node> Substitute( ASTQueries.NodePredAtom filter, Func <IEnumerable <ChildInfo>, NodeKind> subKind, Func <IEnumerable <ChildInfo>, Node> sub, CancellationToken cancel = default(CancellationToken)) { var query = new ASTQueries.NodePred[] { ASTQueries.NodePredFactory.Instance.Star, ASTQueries.NodePredFactory.Instance.MkPredicate(NodeKind.Id) & filter }; if (Root.NodeKind == NodeKind.Id) { if (Root.Eval(query[1], ChildContextKind.AnyChildContext, 0, 0)) { var rootPath = new ChildInfo[] { new ChildInfo(Root, ChildContextKind.AnyChildContext, -1, -1) }; var kind = subKind(rootPath); var m = sub(rootPath); return(m.NodeKind != kind ? this : Factory.Instance.ToAST(m)); } else { return(this); } } AST <Node> crntAst = Factory.Instance.ToAST(Root); this.FindAll( query, (pt, x) => { var list = (LinkedList <ChildInfo>)pt; var prev = list.Last.Previous; var rkind = subKind(pt); if (!ASTQueries.ASTSchema.Instance.CanReplace( prev.Value.Node, list.Last.Value.Node, list.Last.Value.Context, rkind)) { return; } var rep = sub(pt); if (rep.NodeKind != rkind) { return; } var newAST = crntAst == this ? this : Factory.Instance.FromAbsPositions(crntAst.Root, pt); var crnt = ((LinkedList <ChildInfo>)newAST.Path).Last; var subPath = new LinkedList <ChildInfo>(); Node n = null, p = null; int pos = -1; while (crnt != null) { n = pos == -1 ? rep : crnt.Value.Node.ShallowClone(p, pos); pos = crnt.Value.AbsolutePos; p = n; subPath.AddFirst(new ChildInfo(n, crnt.Value.Context, pos, crnt.Value.RelativePos)); crnt = crnt.Previous; } crntAst = Factory.Instance.ToAST(n); }, cancel); crntAst.GetHashCode(); return(crntAst); }